WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] [xen-unstable] [qemu] Update ioemu to qemu 0.8.2.

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-unstable] [qemu] Update ioemu to qemu 0.8.2.
From: Xen patchbot-unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Mon, 07 Aug 2006 19:20:16 +0000
Delivery-date: Mon, 07 Aug 2006 12:23:02 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User chris@xxxxxxxxxxxxxxxxxxxxxxxx
# Node ID 08a11694b109f7c1938494fe64d001e8864a1bbe
# Parent  fd59667e5365483e59c034542f3091f9cc7dc091
[qemu] Update ioemu to qemu 0.8.2.

Signed-off-by: Christian Limpach <Christian.Limpach@xxxxxxxxxxxxx>
---
 tools/ioemu/Changelog               |   19 
 tools/ioemu/Makefile                |   31 
 tools/ioemu/Makefile.target         |   54 -
 tools/ioemu/TODO                    |    2 
 tools/ioemu/VERSION                 |    2 
 tools/ioemu/audio/alsaaudio.c       |   23 
 tools/ioemu/audio/audio.c           |  448 ++++++++-
 tools/ioemu/audio/audio.h           |   46 
 tools/ioemu/audio/audio_int.h       |   42 
 tools/ioemu/audio/audio_template.h  |   33 
 tools/ioemu/audio/coreaudio.c       |   16 
 tools/ioemu/audio/dsound_template.h |   20 
 tools/ioemu/audio/dsoundaudio.c     |    8 
 tools/ioemu/audio/fmodaudio.c       |   10 
 tools/ioemu/audio/noaudio.c         |   40 
 tools/ioemu/audio/ossaudio.c        |   44 
 tools/ioemu/audio/rate_template.h   |    2 
 tools/ioemu/audio/sdlaudio.c        |   10 
 tools/ioemu/audio/wavaudio.c        |    4 
 tools/ioemu/audio/wavcapture.c      |  164 +++
 tools/ioemu/block-cow.c             |    7 
 tools/ioemu/block-qcow.c            |    7 
 tools/ioemu/block-vmdk.c            |    7 
 tools/ioemu/block-vpc.c             |    2 
 tools/ioemu/block-vvfat.c           |    1 
 tools/ioemu/block.c                 |   61 +
 tools/ioemu/block_int.h             |    1 
 tools/ioemu/cocoa.m                 |   60 -
 tools/ioemu/configure               |   45 
 tools/ioemu/console.c               |  170 ++-
 tools/ioemu/cpu-all.h               |  102 +-
 tools/ioemu/cpu-defs.h              |    2 
 tools/ioemu/cpu-exec.c              |   49 
 tools/ioemu/disas.c                 |    4 
 tools/ioemu/dyngen-exec.h           |   27 
 tools/ioemu/dyngen.c                |   92 +
 tools/ioemu/dyngen.h                |    8 
 tools/ioemu/elf.h                   |    2 
 tools/ioemu/exec-all.h              |    2 
 tools/ioemu/exec.c                  |   33 
 tools/ioemu/fpu/softfloat-native.c  |   13 
 tools/ioemu/gdbstub.c               |  131 +-
 tools/ioemu/hw/acpi-dsdt.dsl        |  559 +++++++++++
 tools/ioemu/hw/acpi-dsdt.hex        |  278 +++++
 tools/ioemu/hw/acpi.c               |  615 ++++++++++++
 tools/ioemu/hw/adlib.c              |    4 
 tools/ioemu/hw/apb_pci.c            |  232 ++++
 tools/ioemu/hw/apic.c               |    4 
 tools/ioemu/hw/cdrom.c              |  156 +++
 tools/ioemu/hw/cuda.c               |    2 
 tools/ioemu/hw/es1370.c             |   10 
 tools/ioemu/hw/esp.c                |  538 +++-------
 tools/ioemu/hw/grackle_pci.c        |  156 +++
 tools/ioemu/hw/i8259.c              |    2 
 tools/ioemu/hw/ide.c                |  134 --
 tools/ioemu/hw/lsi53c895a.c         | 1571 +++++++++++++++++++++++++++++++
 tools/ioemu/hw/m48t59.c             |   10 
 tools/ioemu/hw/mips_r4k.c           |    6 
 tools/ioemu/hw/ne2000.c             |    2 
 tools/ioemu/hw/pc.c                 |   59 -
 tools/ioemu/hw/pci.c                | 1489 +----------------------------
 tools/ioemu/hw/pci_host.h           |   93 +
 tools/ioemu/hw/pcnet.c              | 1789 ++++++++++++++++++++++++++++++++++++
 tools/ioemu/hw/pcspk.c              |    4 
 tools/ioemu/hw/pflash_cfi02.c       |  624 ++++++++++++
 tools/ioemu/hw/piix4acpi.c          |    4 
 tools/ioemu/hw/piix_pci.c           |  435 ++++++++
 tools/ioemu/hw/pl050.c              |    2 
 tools/ioemu/hw/ppc_chrp.c           |   20 
 tools/ioemu/hw/ppc_prep.c           |    4 
 tools/ioemu/hw/prep_pci.c           |  167 +++
 tools/ioemu/hw/rtl8139.c            | 1494 +++++++++++++++++++++---------
 tools/ioemu/hw/sb16.c               |   94 +
 tools/ioemu/hw/scsi-disk.c          |  478 +++++++++
 tools/ioemu/hw/sh7750.c             |    2 
 tools/ioemu/hw/slavio_intctl.c      |    2 
 tools/ioemu/hw/slavio_timer.c       |    2 
 tools/ioemu/hw/sun4m.c              |   14 
 tools/ioemu/hw/sun4u.c              |   18 
 tools/ioemu/hw/unin_pci.c           |  261 +++++
 tools/ioemu/hw/usb-hid.c            |   14 
 tools/ioemu/hw/usb-hub.c            |   26 
 tools/ioemu/hw/usb-msd.c            |  402 ++++++++
 tools/ioemu/hw/usb-ohci.c           | 1190 +++++++++++++++++++++++
 tools/ioemu/hw/usb-uhci.c           |   22 
 tools/ioemu/hw/usb.h                |   18 
 tools/ioemu/hw/versatile_pci.c      |  119 ++
 tools/ioemu/hw/versatilepb.c        |  216 ++++
 tools/ioemu/hw/vga.c                |  137 +-
 tools/ioemu/hw/vga_int.h            |    9 
 tools/ioemu/hw/vga_template.h       |  234 ++--
 tools/ioemu/kqemu.c                 |   11 
 tools/ioemu/loader.c                |    2 
 tools/ioemu/monitor.c               |  164 ++-
 tools/ioemu/osdep.c                 |   22 
 tools/ioemu/osdep.h                 |    2 
 tools/ioemu/pc-bios/README          |    8 
 tools/ioemu/pc-bios/bios.diff       |   87 +
 tools/ioemu/pc-bios/vgabios.diff    |  825 +++-------------
 tools/ioemu/qemu-doc.texi           |  250 +++--
 tools/ioemu/qemu-img.c              |   33 
 tools/ioemu/sdl.c                   |   27 
 tools/ioemu/tap-win32.c             |    8 
 tools/ioemu/target-i386/exec.h      |    3 
 tools/ioemu/target-i386/helper.c    |   39 
 tools/ioemu/target-i386/helper2.c   |   33 
 tools/ioemu/target-i386/op.c        |   15 
 tools/ioemu/target-i386/translate.c |   93 +
 tools/ioemu/tests/Makefile          |    3 
 tools/ioemu/tests/test-i386.c       |   22 
 tools/ioemu/usb-linux.c             |   44 
 tools/ioemu/vl.c                    | 1284 +++++++++++++++++--------
 tools/ioemu/vl.h                    |  137 ++
 tools/ioemu/vnc.c                   |  258 ++++-
 tools/ioemu/vnchextile.h            |   48 
 ioemu/pc-bios/video.x               |    0 
 116 files changed, 14710 insertions(+), 4273 deletions(-)

diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/Changelog
--- a/tools/ioemu/Changelog     Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/Changelog     Mon Aug 07 18:25:30 2006 +0100
@@ -1,3 +1,22 @@ version 0.8.1:
+version 0.8.2:
+
+  - ACPI support
+  - PC VGA BIOS fixes
+  - switch to OpenBios for SPARC targets (Blue Swirl)
+  - VNC server fixes
+  - MIPS FPU support (Marius Groeger)
+  - Solaris/SPARC host support (Ben Taylor)
+  - PPC breakpoints and single stepping (Jason Wessel)
+  - USB updates (Paul Brook)
+  - UDP/TCP/telnet character devices (Jason Wessel)
+  - Windows sparse file support (Frediano Ziglio)
+  - RTL8139 NIC TCP segmentation offloading (Igor Kovalenko)
+  - PCNET NIC support (Antony T Curtis)
+  - Support for variable frequency host CPUs
+  - Workaround for win32 SMP hosts
+  - Support for AMD Flash memories (Jocelyn Mayer)
+  - Audio capture to WAV files support (malc)
+
 version 0.8.1:
 
   - USB tablet support (Brad Campbell, Anthony Liguori)
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/Makefile
--- a/tools/ioemu/Makefile      Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/Makefile      Mon Aug 07 18:25:30 2006 +0100
@@ -1,11 +1,19 @@ XEN_ROOT=../..
+# Makefile for QEMU.
+
 XEN_ROOT=../..
 include $(XEN_ROOT)/tools/Rules.mk
 
 -include config-host.mak
 
+.PHONY: all clean distclean dvi info install install-doc tar tarbin \
+       speed test test2 html dvi info
+
 CFLAGS+=-Wall -O2 -g -fno-strict-aliasing -I.
 ifdef CONFIG_DARWIN
 CFLAGS+= -mdynamic-no-pic
+endif
+ifeq ($(ARCH),sparc)
+CFLAGS+=-mcpu=ultrasparc
 endif
 LDFLAGS=-g
 LIBS=
@@ -20,11 +28,15 @@ DOCS=
 DOCS=
 endif
 
-all: $(DOCS)
-       for d in $(TARGET_DIRS); do \
-       $(MAKE) -C $$d $@ || exit 1 ; \
-        done
+TOOLS=
 
+all: $(TOOLS) $(DOCS) recurse-all
+
+subdir-%:
+       $(MAKE) -C $(subst subdir-,,$@) all
+
+recurse-all: $(patsubst %,subdir-%, $(TARGET_DIRS))
+        
 qemu-img$(EXESUF): qemu-img.c block.c block-cow.c block-qcow.c aes.c 
block-vmdk.c block-cloop.c block-dmg.c block-bochs.c block-vpc.c block-vvfat.c
        $(CC) -DQEMU_TOOL $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ -lz $(LIBS)
 
@@ -42,6 +54,7 @@ clean:
 
 distclean: clean
        rm -f config-host.mak config-host.h $(DOCS)
+       rm -f qemu-{doc,tech}.{info,aux,cp,dvi,fn,info,ky,log,pg,toc,tp,vr}
        for d in $(TARGET_DIRS); do \
        rm -rf $$d || exit 1 ; \
         done
@@ -63,7 +76,7 @@ install: all $(if $(BUILD_DOCS),install-
 #      $(INSTALL) -m 755 -s $(TOOLS) "$(DESTDIR)$(bindir)"
 #      mkdir -p "$(DESTDIR)$(datadir)"
 #      for x in bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \
-#                      video.x proll.elf linux_boot.bin; do \
+#                      video.x openbios-sparc32 linux_boot.bin; do \
 #              $(INSTALL) -m 644 $(SRC_PATH)/pc-bios/$$x 
"$(DESTDIR)$(datadir)"; \
 #      done
 ifndef CONFIG_WIN32
@@ -106,6 +119,12 @@ qemu-img.1: qemu-img.texi
        perl -w $(SRC_PATH)/texi2pod.pl $< qemu-img.pod
        pod2man --section=1 --center=" " --release=" " qemu-img.pod > $@
 
+info: qemu-doc.info qemu-tech.info
+
+dvi: qemu-doc.dvi qemu-tech.dvi
+
+html: qemu-doc.html qemu-tech.html
+
 FILE=qemu-$(shell cat VERSION)
 
 # tar release (use 'make -k tar' on a checkouted tree)
@@ -138,7 +157,7 @@ tarbin:
        $(datadir)/vgabios-cirrus.bin \
        $(datadir)/ppc_rom.bin \
        $(datadir)/video.x \
-       $(datadir)/proll.elf \
+       $(datadir)/openbios-sparc32 \
        $(datadir)/linux_boot.bin \
        $(docdir)/qemu-doc.html \
        $(docdir)/qemu-tech.html \
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/Makefile.target
--- a/tools/ioemu/Makefile.target       Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/Makefile.target       Mon Aug 07 18:25:30 2006 +0100
@@ -40,6 +40,11 @@ ifeq ($(TARGET_ARCH),arm)
     TARGET_ARCH2=armeb
   endif
 endif
+ifeq ($(TARGET_ARCH),sh4)
+  ifeq ($(TARGET_WORDS_BIGENDIAN),yes)
+    TARGET_ARCH2=sh4eb
+  endif
+endif
 ifeq ($(TARGET_ARCH),mips)
   ifneq ($(TARGET_WORDS_BIGENDIAN),yes)
     TARGET_ARCH2=mipsel
@@ -114,17 +119,24 @@ endif
 endif
 
 ifeq ($(ARCH),sparc)
-CFLAGS+=-m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
+ifeq ($(CONFIG_SOLARIS),yes)
+CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g2 -ffixed-g3
+LDFLAGS+=-m32
+OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -fno-omit-frame-pointer -ffixed-i0
+else
+CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
 LDFLAGS+=-m32
 OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0
 HELPER_CFLAGS=$(CFLAGS) -ffixed-i0 -mflat
 # -static is used to avoid g1/g3 usage by the dynamic linker
 LDFLAGS+=-Wl,-T,$(SRC_PATH)/sparc.ld -static
 endif
+endif
 
 ifeq ($(ARCH),sparc64)
-CFLAGS+=-m64 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
+CFLAGS+=-mcpu=ultrasparc -m64 -ffixed-g1 -ffixed-g4 -ffixed-g5 -ffixed-g7
 LDFLAGS+=-m64
+LDFLAGS+=-Wl,-T,$(SRC_PATH)/sparc64.ld
 OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0
 endif
 
@@ -186,7 +198,12 @@ main.o: CFLAGS+=-p
 main.o: CFLAGS+=-p
 endif
 
-OBJS= elfload.o main.o syscall.o mmap.o signal.o path.o osdep.o thunk.o 
+OBJS= main.o syscall.o mmap.o signal.o path.o osdep.o thunk.o \
+      elfload.o linuxload.o
+ifdef TARGET_HAS_BFLT
+OBJS+= flatload.o
+endif
+
 ifeq ($(TARGET_ARCH), i386)
 OBJS+= vm86.o
 endif
@@ -323,18 +340,23 @@ ifdef CONFIG_ADLIB
 ifdef CONFIG_ADLIB
 SOUND_HW += fmopl.o adlib.o
 endif
+AUDIODRV+= wavcapture.o
+
+# SCSI layer
+VL_OBJS+= scsi-disk.o cdrom.o lsi53c895a.o
 
 # USB layer
-VL_OBJS+= usb.o usb-hub.o usb-uhci.o usb-linux.o usb-hid.o
+VL_OBJS+= usb.o usb-hub.o usb-linux.o usb-hid.o usb-ohci.o usb-msd.o
 
 # PCI network cards
-VL_OBJS+= ne2000.o rtl8139.o
+VL_OBJS+= ne2000.o rtl8139.o pcnet.o
 
 ifeq ($(TARGET_BASE_ARCH), i386)
 # Hardware support
 VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
 VL_OBJS+= fdc.o mc146818rtc.o serial.o pc.o
-VL_OBJS+= cirrus_vga.o mixeng.o parallel.o
+VL_OBJS+= cirrus_vga.o mixeng.o parallel.o acpi.o piix_pci.o
+VL_OBJS+= usb-uhci.o
 VL_OBJS+= piix4acpi.o
 VL_OBJS+= xenstore.o
 DEFINES += -DHAS_AUDIO
@@ -343,6 +365,7 @@ VL_OBJS+= ppc.o ide.o pckbd.o ps2.o vga.
 VL_OBJS+= ppc.o ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
 VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o
 VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o heathrow_pic.o mixeng.o
+VL_OBJS+= grackle_pci.o prep_pci.o unin_pci.o
 DEFINES += -DHAS_AUDIO
 endif
 ifeq ($(TARGET_ARCH), mips)
@@ -351,7 +374,7 @@ endif
 endif
 ifeq ($(TARGET_BASE_ARCH), sparc)
 ifeq ($(TARGET_ARCH), sparc64)
-VL_OBJS+= sun4u.o ide.o pckbd.o ps2.o vga.o
+VL_OBJS+= sun4u.o ide.o pckbd.o ps2.o vga.o apb_pci.o
 VL_OBJS+= fdc.o mc146818rtc.o serial.o m48t59.o
 VL_OBJS+= cirrus_vga.o parallel.o
 else
@@ -362,6 +385,7 @@ ifeq ($(TARGET_BASE_ARCH), arm)
 ifeq ($(TARGET_BASE_ARCH), arm)
 VL_OBJS+= integratorcp.o versatilepb.o ps2.o smc91c111.o arm_pic.o arm_timer.o
 VL_OBJS+= arm_boot.o pl011.o pl050.o pl080.o pl110.o pl190.o
+VL_OBJS+= versatile_pci.o
 endif
 ifeq ($(TARGET_BASE_ARCH), sh4)
 VL_OBJS+= shix.o sh7750.o sh7750_regnames.o tc58128.o
@@ -399,7 +423,7 @@ ifndef CONFIG_DARWIN
 ifndef CONFIG_DARWIN
 ifndef CONFIG_WIN32
 ifndef CONFIG_SOLARIS
-VL_LIBS=-lutil
+VL_LIBS=-lutil -lrt
 endif
 endif
 endif
@@ -410,6 +434,11 @@ endif
 
 ifeq ($(ARCH),ia64)
 VL_LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/ia64.ld
+endif
+
+ifeq ($(ARCH),sparc64)
+VL_LDFLAGS+=-m64
+VL_LDFLAGS+=-Wl,-T,$(SRC_PATH)/sparc64.ld
 endif
 
 ifdef CONFIG_WIN32
@@ -490,6 +519,13 @@ endif
 endif
 
 loader.o: loader.c elf_ops.h
+
+acpi.o: acpi.c acpi-dsdt.hex
+
+ifdef BUILD_ACPI_TABLES
+$(SRC_PATH)/hw/acpi-dsdt.hex: acpi-dsdt.dsl
+       iasl -tc -p $@ $<
+endif
 
 ifeq ($(TARGET_ARCH), sh4)
 op.o: op.c op_mem.c cpu.h
@@ -501,6 +537,8 @@ tc58128.o: tc58128.c
 tc58128.o: tc58128.c
 endif
 
+$(OBJS) $(LIBOBJS) $(VL_OBJS): config.h ../config-host.h
+
 %.o: %.c
        $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
 
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/TODO
--- a/tools/ioemu/TODO  Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/TODO  Mon Aug 07 18:25:30 2006 +0100
@@ -1,24 +1,20 @@ short term:
 short term:
 ----------
+- cycle counter for all archs
+- cpu_interrupt() win32/SMP fix
 - support variable tsc freq
-- cpu_interrupt() win32/SMP fix
 - USB host async
 - IDE async
 - debug option in 'configure' script + disable -fomit-frame-pointer
 - Precise VGA timings for old games/demos (malc patch)
 - merge PIC spurious interrupt patch
-- merge Solaris patch
 - warning for OS/2: must not use 128 MB memory (merge bochs cmos patch ?)
 - config file (at least for windows/Mac OS X)
-- commit message if execution of code in IO memory
 - update doc: PCI infos.
-- VNC patch + Synaptic patch.
 - basic VGA optimizations
-- physical memory cache (reduce qemu-fast address space size to about 32 MB)
 - better code fetch (different exception handling + CS.limit support)
 - do not resize vga if invalid size.
 - avoid looping if only exceptions
-- cycle counter for all archs
 - TLB code protection support for PPC
 - see openMosix Doc 
 - disable SMC handling for ARM/SPARC/PPC (not finished)
@@ -31,12 +27,10 @@ short term:
 - fix CCOP optimisation
 - fix all remaining thread lock issues (must put TBs in a specific invalid
   state, find a solution for tb_flush()).
-- fix arm fpu rounding (at least for float->integer conversions)
 
 ppc specific:
 ------------
 - TLB invalidate not needed if msr_pr changes
-- SPR_ENCODE() not useful
 - enable shift optimizations ?
 
 linux-user specific:
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/VERSION
--- a/tools/ioemu/VERSION       Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/VERSION       Mon Aug 07 18:25:30 2006 +0100
@@ -1,1 +1,1 @@ 0.8.1
-0.8.1
\ No newline at end of file
+0.8.2
\ No newline at end of file
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/audio/alsaaudio.c
--- a/tools/ioemu/audio/alsaaudio.c     Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/audio/alsaaudio.c     Mon Aug 07 18:25:30 2006 +0100
@@ -61,8 +61,8 @@ static struct {
     .size_in_usec_in = 1,
     .size_in_usec_out = 1,
 #endif
-    .pcm_name_out = "hw:0,0",
-    .pcm_name_in = "hw:0,0",
+    .pcm_name_out = "default",
+    .pcm_name_in = "default",
 #ifdef HIGH_LATENCY
     .buffer_size_in = 400000,
     .period_size_in = 400000 / 4,
@@ -606,7 +606,6 @@ static int alsa_run_out (HWVoiceOut *hw)
                 }
             }
 
-            mixeng_clear (src, written);
             rpos = (rpos + written) % hw->samples;
             samples -= written;
             len -= written;
@@ -663,12 +662,9 @@ static int alsa_init_out (HWVoiceOut *hw
     obt_as.freq = obt.freq;
     obt_as.nchannels = obt.nchannels;
     obt_as.fmt = effective_fmt;
-
-    audio_pcm_init_info (
-        &hw->info,
-        &obt_as,
-        audio_need_to_swap_endian (endianness)
-        );
+    obt_as.endianness = endianness;
+
+    audio_pcm_init_info (&hw->info, &obt_as);
     hw->samples = obt.samples;
 
     alsa->pcm_buf = audio_calloc (AUDIO_FUNC, obt.samples, 1 << 
hw->info.shift);
@@ -752,12 +748,9 @@ static int alsa_init_in (HWVoiceIn *hw, 
     obt_as.freq = obt.freq;
     obt_as.nchannels = obt.nchannels;
     obt_as.fmt = effective_fmt;
-
-    audio_pcm_init_info (
-        &hw->info,
-        &obt_as,
-        audio_need_to_swap_endian (endianness)
-        );
+    obt_as.endianness = endianness;
+
+    audio_pcm_init_info (&hw->info, &obt_as);
     hw->samples = obt.samples;
 
     alsa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << 
hw->info.shift);
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/audio/audio.c
--- a/tools/ioemu/audio/audio.c Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/audio/audio.c Mon Aug 07 18:25:30 2006 +0100
@@ -29,6 +29,7 @@
 /* #define DEBUG_PLIVE */
 /* #define DEBUG_LIVE */
 /* #define DEBUG_OUT */
+/* #define DEBUG_CAPTURE */
 
 #define SW_NAME(sw) (sw)->name ? (sw)->name : "unknown"
 
@@ -137,7 +138,7 @@ int audio_bug (const char *funcname, int
     if (cond) {
         static int shown;
 
-        AUD_log (NULL, "Error a bug that was just triggered in %s\n", 
funcname);
+        AUD_log (NULL, "A bug was just triggered in %s\n", funcname);
         if (!shown) {
             shown = 1;
             AUD_log (NULL, "Save all your work and restart without audio\n");
@@ -509,14 +510,28 @@ static void audio_print_settings (audset
         AUD_log (NULL, "invalid(%d)", as->fmt);
         break;
     }
+
+    AUD_log (NULL, " endianness=");
+    switch (as->endianness) {
+    case 0:
+        AUD_log (NULL, "little");
+        break;
+    case 1:
+        AUD_log (NULL, "big");
+        break;
+    default:
+        AUD_log (NULL, "invalid");
+        break;
+    }
     AUD_log (NULL, "\n");
 }
 
-static int audio_validate_settigs (audsettings_t *as)
+static int audio_validate_settings (audsettings_t *as)
 {
     int invalid;
 
     invalid = as->nchannels != 1 && as->nchannels != 2;
+    invalid |= as->endianness != 0 && as->endianness != 1;
 
     switch (as->fmt) {
     case AUD_FMT_S8:
@@ -530,11 +545,7 @@ static int audio_validate_settigs (audse
     }
 
     invalid |= as->freq <= 0;
-
-    if (invalid) {
-        return -1;
-    }
-    return 0;
+    return invalid ? -1 : 0;
 }
 
 static int audio_pcm_info_eq (struct audio_pcm_info *info, audsettings_t *as)
@@ -556,14 +567,11 @@ static int audio_pcm_info_eq (struct aud
     return info->freq == as->freq
         && info->nchannels == as->nchannels
         && info->sign == sign
-        && info->bits == bits;
-}
-
-void audio_pcm_init_info (
-    struct audio_pcm_info *info,
-    audsettings_t *as,
-    int swap_endian
-    )
+        && info->bits == bits
+        && info->swap_endianness == (as->endianness != AUDIO_HOST_ENDIANNESS);
+}
+
+void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as)
 {
     int bits = 8, sign = 0;
 
@@ -587,7 +595,7 @@ void audio_pcm_init_info (
     info->shift = (as->nchannels == 2) + (bits == 16);
     info->align = (1 << info->shift) - 1;
     info->bytes_per_second = info->freq << info->shift;
-    info->swap_endian = swap_endian;
+    info->swap_endianness = (as->endianness != AUDIO_HOST_ENDIANNESS);
 }
 
 void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
@@ -609,7 +617,7 @@ void audio_pcm_info_clear_buf (struct au
             int shift = info->nchannels - 1;
             short s = INT16_MAX;
 
-            if (info->swap_endian) {
+            if (info->swap_endianness) {
                 s = bswap16 (s);
             }
 
@@ -618,6 +626,143 @@ void audio_pcm_info_clear_buf (struct au
             }
         }
     }
+}
+
+/*
+ * Capture
+ */
+static void noop_conv (st_sample_t *dst, const void *src,
+                       int samples, volume_t *vol)
+{
+    (void) src;
+    (void) dst;
+    (void) samples;
+    (void) vol;
+}
+
+static CaptureVoiceOut *audio_pcm_capture_find_specific (
+    AudioState *s,
+    audsettings_t *as
+    )
+{
+    CaptureVoiceOut *cap;
+
+    for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) {
+        if (audio_pcm_info_eq (&cap->hw.info, as)) {
+            return cap;
+        }
+    }
+    return NULL;
+}
+
+static void audio_notify_capture (CaptureVoiceOut *cap, audcnotification_e cmd)
+{
+    struct capture_callback *cb;
+
+#ifdef DEBUG_CAPTURE
+    dolog ("notification %d sent\n", cmd);
+#endif
+    for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) {
+        cb->ops.notify (cb->opaque, cmd);
+    }
+}
+
+static void audio_capture_maybe_changed (CaptureVoiceOut *cap, int enabled)
+{
+    if (cap->hw.enabled != enabled) {
+        audcnotification_e cmd;
+        cap->hw.enabled = enabled;
+        cmd = enabled ? AUD_CNOTIFY_ENABLE : AUD_CNOTIFY_DISABLE;
+        audio_notify_capture (cap, cmd);
+    }
+}
+
+static void audio_recalc_and_notify_capture (CaptureVoiceOut *cap)
+{
+    HWVoiceOut *hw = &cap->hw;
+    SWVoiceOut *sw;
+    int enabled = 0;
+
+    for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
+        if (sw->active) {
+            enabled = 1;
+            break;
+        }
+    }
+    audio_capture_maybe_changed (cap, enabled);
+}
+
+static void audio_detach_capture (HWVoiceOut *hw)
+{
+    SWVoiceCap *sc = hw->cap_head.lh_first;
+
+    while (sc) {
+        SWVoiceCap *sc1 = sc->entries.le_next;
+        SWVoiceOut *sw = &sc->sw;
+        CaptureVoiceOut *cap = sc->cap;
+        int was_active = sw->active;
+
+        if (sw->rate) {
+            st_rate_stop (sw->rate);
+            sw->rate = NULL;
+        }
+
+        LIST_REMOVE (sw, entries);
+        LIST_REMOVE (sc, entries);
+        qemu_free (sc);
+        if (was_active) {
+            /* We have removed soft voice from the capture:
+               this might have changed the overall status of the capture
+               since this might have been the only active voice */
+            audio_recalc_and_notify_capture (cap);
+        }
+        sc = sc1;
+    }
+}
+
+static int audio_attach_capture (AudioState *s, HWVoiceOut *hw)
+{
+    CaptureVoiceOut *cap;
+
+    audio_detach_capture (hw);
+    for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) {
+        SWVoiceCap *sc;
+        SWVoiceOut *sw;
+        HWVoiceOut *hw_cap = &cap->hw;
+
+        sc = audio_calloc (AUDIO_FUNC, 1, sizeof (*sc));
+        if (!sc) {
+            dolog ("Could not allocate soft capture voice (%zu bytes)\n",
+                   sizeof (*sc));
+            return -1;
+        }
+
+        sc->cap = cap;
+        sw = &sc->sw;
+        sw->hw = hw_cap;
+        sw->info = hw->info;
+        sw->empty = 1;
+        sw->active = hw->enabled;
+        sw->conv = noop_conv;
+        sw->ratio = ((int64_t) hw_cap->info.freq << 32) / sw->info.freq;
+        sw->rate = st_rate_start (sw->info.freq, hw_cap->info.freq);
+        if (!sw->rate) {
+            dolog ("Could not start rate conversion for `%s'\n", SW_NAME (sw));
+            qemu_free (sw);
+            return -1;
+        }
+        LIST_INSERT_HEAD (&hw_cap->sw_head, sw, entries);
+        LIST_INSERT_HEAD (&hw->cap_head, sc, entries);
+#ifdef DEBUG_CAPTURE
+        asprintf (&sw->name, "for %p %d,%d,%d",
+                  hw, sw->info.freq, sw->info.bits, sw->info.nchannels);
+        dolog ("Added %s active = %d\n", sw->name, sw->active);
+#endif
+        if (sw->active) {
+            audio_capture_maybe_changed (cap, 1);
+        }
+    }
+    return 0;
 }
 
 /*
@@ -796,6 +941,9 @@ int audio_pcm_sw_write (SWVoiceOut *sw, 
     }
 
     if (live == hwsamples) {
+#ifdef DEBUG_OUT
+        dolog ("%s is full %d\n", sw->name, live);
+#endif
         return 0;
     }
 
@@ -914,19 +1062,14 @@ void AUD_set_active_out (SWVoiceOut *sw,
     hw = sw->hw;
     if (sw->active != on) {
         SWVoiceOut *temp_sw;
+        SWVoiceCap *sc;
 
         if (on) {
-            int total;
-
             hw->pending_disable = 0;
             if (!hw->enabled) {
                 hw->enabled = 1;
                 hw->pcm_ops->ctl_out (hw, VOICE_ENABLE);
             }
-
-            if (sw->empty) {
-                total = 0;
-            }
         }
         else {
             if (hw->enabled) {
@@ -940,6 +1083,13 @@ void AUD_set_active_out (SWVoiceOut *sw,
                 hw->pending_disable = nb_active == 1;
             }
         }
+
+        for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) {
+            sc->sw.active = hw->enabled;
+            if (hw->enabled) {
+                audio_capture_maybe_changed (sc->cap, 1);
+            }
+        }
         sw->active = on;
     }
 }
@@ -997,7 +1147,7 @@ static int audio_get_avail (SWVoiceIn *s
     }
 
     ldebug (
-        "%s: get_avail live %d ret %lld\n",
+        "%s: get_avail live %d ret %" PRId64 "\n",
         SW_NAME (sw),
         live, (((int64_t) live << 32) / sw->ratio) << sw->info.shift
         );
@@ -1023,7 +1173,7 @@ static int audio_get_free (SWVoiceOut *s
     dead = sw->hw->samples - live;
 
 #ifdef DEBUG_OUT
-    dolog ("%s: get_free live %d dead %d ret %lld\n",
+    dolog ("%s: get_free live %d dead %d ret %" PRId64 "\n",
            SW_NAME (sw),
            live, dead, (((int64_t) dead << 32) / sw->ratio) << sw->info.shift);
 #endif
@@ -1031,6 +1181,43 @@ static int audio_get_free (SWVoiceOut *s
     return (((int64_t) dead << 32) / sw->ratio) << sw->info.shift;
 }
 
+static void audio_capture_mix_and_clear (HWVoiceOut *hw, int rpos, int samples)
+{
+    int n;
+
+    if (hw->enabled) {
+        SWVoiceCap *sc;
+
+        for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) {
+            SWVoiceOut *sw = &sc->sw;
+            int rpos2 = rpos;
+
+            n = samples;
+            while (n) {
+                int till_end_of_hw = hw->samples - rpos2;
+                int to_write = audio_MIN (till_end_of_hw, n);
+                int bytes = to_write << hw->info.shift;
+                int written;
+
+                sw->buf = hw->mix_buf + rpos2;
+                written = audio_pcm_sw_write (sw, NULL, bytes);
+                if (written - bytes) {
+                    dolog ("Could not mix %d bytes into a capture "
+                           "buffer, mixed %d\n",
+                           bytes, written);
+                    break;
+                }
+                n -= to_write;
+                rpos2 = (rpos2 + to_write) % hw->samples;
+            }
+        }
+    }
+
+    n = audio_MIN (samples, hw->samples - rpos);
+    mixeng_clear (hw->mix_buf + rpos, n);
+    mixeng_clear (hw->mix_buf, samples - n);
+}
+
 static void audio_run_out (AudioState *s)
 {
     HWVoiceOut *hw = NULL;
@@ -1038,7 +1225,7 @@ static void audio_run_out (AudioState *s
 
     while ((hw = audio_pcm_hw_find_any_enabled_out (s, hw))) {
         int played;
-        int live, free, nb_live, cleanup_required;
+        int live, free, nb_live, cleanup_required, prev_rpos;
 
         live = audio_pcm_hw_get_live_out2 (hw, &nb_live);
         if (!nb_live) {
@@ -1051,12 +1238,17 @@ static void audio_run_out (AudioState *s
         }
 
         if (hw->pending_disable && !nb_live) {
+            SWVoiceCap *sc;
 #ifdef DEBUG_OUT
             dolog ("Disabling voice\n");
 #endif
             hw->enabled = 0;
             hw->pending_disable = 0;
             hw->pcm_ops->ctl_out (hw, VOICE_DISABLE);
+            for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) {
+                sc->sw.active = 0;
+                audio_recalc_and_notify_capture (sc->cap);
+            }
             continue;
         }
 
@@ -1072,6 +1264,7 @@ static void audio_run_out (AudioState *s
             continue;
         }
 
+        prev_rpos = hw->rpos;
         played = hw->pcm_ops->run_out (hw);
         if (audio_bug (AUDIO_FUNC, hw->rpos >= hw->samples)) {
             dolog ("hw->rpos=%d hw->samples=%d played=%d\n",
@@ -1085,6 +1278,7 @@ static void audio_run_out (AudioState *s
 
         if (played) {
             hw->ts_helper += played;
+            audio_capture_mix_and_clear (hw, prev_rpos, played);
         }
 
         cleanup_required = 0;
@@ -1115,15 +1309,18 @@ static void audio_run_out (AudioState *s
         }
 
         if (cleanup_required) {
-        restart:
-            for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
+            SWVoiceOut *sw1;
+
+            sw = hw->sw_head.lh_first;
+            while (sw) {
+                sw1 = sw->entries.le_next;
                 if (!sw->active && !sw->callback.fn) {
 #ifdef DEBUG_PLIVE
                     dolog ("Finishing with old voice\n");
 #endif
                     audio_close_out (s, sw);
-                    goto restart; /* play it safe */
                 }
+                sw = sw1;
             }
         }
     }
@@ -1158,12 +1355,60 @@ static void audio_run_in (AudioState *s)
     }
 }
 
+static void audio_run_capture (AudioState *s)
+{
+    CaptureVoiceOut *cap;
+
+    for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) {
+        int live, rpos, captured;
+        HWVoiceOut *hw = &cap->hw;
+        SWVoiceOut *sw;
+
+        captured = live = audio_pcm_hw_get_live_out (hw);
+        rpos = hw->rpos;
+        while (live) {
+            int left = hw->samples - rpos;
+            int to_capture = audio_MIN (live, left);
+            st_sample_t *src;
+            struct capture_callback *cb;
+
+            src = hw->mix_buf + rpos;
+            hw->clip (cap->buf, src, to_capture);
+            mixeng_clear (src, to_capture);
+
+            for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) {
+                cb->ops.capture (cb->opaque, cap->buf,
+                                 to_capture << hw->info.shift);
+            }
+            rpos = (rpos + to_capture) % hw->samples;
+            live -= to_capture;
+        }
+        hw->rpos = rpos;
+
+        for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
+            if (!sw->active && sw->empty) {
+                continue;
+            }
+
+            if (audio_bug (AUDIO_FUNC, captured > sw->total_hw_samples_mixed)) 
{
+                dolog ("captured=%d sw->total_hw_samples_mixed=%d\n",
+                       captured, sw->total_hw_samples_mixed);
+                captured = sw->total_hw_samples_mixed;
+            }
+
+            sw->total_hw_samples_mixed -= captured;
+            sw->empty = sw->total_hw_samples_mixed == 0;
+        }
+    }
+}
+
 static void audio_timer (void *opaque)
 {
     AudioState *s = opaque;
 
     audio_run_out (s);
     audio_run_in (s);
+    audio_run_capture (s);
 
     qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks);
 }
@@ -1327,8 +1572,19 @@ static void audio_atexit (void)
     HWVoiceIn *hwi = NULL;
 
     while ((hwo = audio_pcm_hw_find_any_enabled_out (s, hwo))) {
+        SWVoiceCap *sc;
+
         hwo->pcm_ops->ctl_out (hwo, VOICE_DISABLE);
         hwo->pcm_ops->fini_out (hwo);
+
+        for (sc = hwo->cap_head.lh_first; sc; sc = sc->entries.le_next) {
+            CaptureVoiceOut *cap = sc->cap;
+            struct capture_callback *cb;
+
+            for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) {
+                cb->ops.destroy (cb->opaque);
+            }
+        }
     }
 
     while ((hwi = audio_pcm_hw_find_any_enabled_in (s, hwi))) {
@@ -1383,6 +1639,7 @@ AudioState *AUD_init (void)
 
     LIST_INIT (&s->hw_head_out);
     LIST_INIT (&s->hw_head_in);
+    LIST_INIT (&s->cap_head);
     atexit (audio_atexit);
 
     s->ts = qemu_new_timer (vm_clock, audio_timer, s);
@@ -1479,3 +1736,136 @@ AudioState *AUD_init (void)
     qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks);
     return s;
 }
+
+CaptureVoiceOut *AUD_add_capture (
+    AudioState *s,
+    audsettings_t *as,
+    struct audio_capture_ops *ops,
+    void *cb_opaque
+    )
+{
+    CaptureVoiceOut *cap;
+    struct capture_callback *cb;
+
+    if (!s) {
+        /* XXX suppress */
+        s = &glob_audio_state;
+    }
+
+    if (audio_validate_settings (as)) {
+        dolog ("Invalid settings were passed when trying to add capture\n");
+        audio_print_settings (as);
+        goto err0;
+    }
+
+    cb = audio_calloc (AUDIO_FUNC, 1, sizeof (*cb));
+    if (!cb) {
+        dolog ("Could not allocate capture callback information, size %zu\n",
+               sizeof (*cb));
+        goto err0;
+    }
+    cb->ops = *ops;
+    cb->opaque = cb_opaque;
+
+    cap = audio_pcm_capture_find_specific (s, as);
+    if (cap) {
+        LIST_INSERT_HEAD (&cap->cb_head, cb, entries);
+        return cap;
+    }
+    else {
+        HWVoiceOut *hw;
+        CaptureVoiceOut *cap;
+
+        cap = audio_calloc (AUDIO_FUNC, 1, sizeof (*cap));
+        if (!cap) {
+            dolog ("Could not allocate capture voice, size %zu\n",
+                   sizeof (*cap));
+            goto err1;
+        }
+
+        hw = &cap->hw;
+        LIST_INIT (&hw->sw_head);
+        LIST_INIT (&cap->cb_head);
+
+        /* XXX find a more elegant way */
+        hw->samples = 4096 * 4;
+        hw->mix_buf = audio_calloc (AUDIO_FUNC, hw->samples,
+                                    sizeof (st_sample_t));
+        if (!hw->mix_buf) {
+            dolog ("Could not allocate capture mix buffer (%d samples)\n",
+                   hw->samples);
+            goto err2;
+        }
+
+        audio_pcm_init_info (&hw->info, as);
+
+        cap->buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
+        if (!cap->buf) {
+            dolog ("Could not allocate capture buffer "
+                   "(%d samples, each %d bytes)\n",
+                   hw->samples, 1 << hw->info.shift);
+            goto err3;
+        }
+
+        hw->clip = mixeng_clip
+            [hw->info.nchannels == 2]
+            [hw->info.sign]
+            [hw->info.swap_endianness]
+            [hw->info.bits == 16];
+
+        LIST_INSERT_HEAD (&s->cap_head, cap, entries);
+        LIST_INSERT_HEAD (&cap->cb_head, cb, entries);
+
+        hw = NULL;
+        while ((hw = audio_pcm_hw_find_any_out (s, hw))) {
+            audio_attach_capture (s, hw);
+        }
+        return cap;
+
+    err3:
+        qemu_free (cap->hw.mix_buf);
+    err2:
+        qemu_free (cap);
+    err1:
+        qemu_free (cb);
+    err0:
+        return NULL;
+    }
+}
+
+void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque)
+{
+    struct capture_callback *cb;
+
+    for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) {
+        if (cb->opaque == cb_opaque) {
+            cb->ops.destroy (cb_opaque);
+            LIST_REMOVE (cb, entries);
+            qemu_free (cb);
+
+            if (!cap->cb_head.lh_first) {
+                SWVoiceOut *sw = cap->hw.sw_head.lh_first, *sw1;
+
+                while (sw) {
+                    SWVoiceCap *sc = (SWVoiceCap *) sw;
+#ifdef DEBUG_CAPTURE
+                    dolog ("freeing %s\n", sw->name);
+#endif
+
+                    sw1 = sw->entries.le_next;
+                    if (sw->rate) {
+                        st_rate_stop (sw->rate);
+                        sw->rate = NULL;
+                    }
+                    LIST_REMOVE (sw, entries);
+                    LIST_REMOVE (sc, entries);
+                    qemu_free (sc);
+                    sw = sw1;
+                }
+                LIST_REMOVE (cap, entries);
+                qemu_free (cap);
+            }
+            return;
+        }
+    }
+}
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/audio/audio.h
--- a/tools/ioemu/audio/audio.h Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/audio/audio.h Mon Aug 07 18:25:30 2006 +0100
@@ -24,6 +24,7 @@
 #ifndef QEMU_AUDIO_H
 #define QEMU_AUDIO_H
 
+#include "config.h"
 #include "sys-queue.h"
 
 typedef void (*audio_callback_fn_t) (void *opaque, int avail);
@@ -35,14 +36,44 @@ typedef enum {
     AUD_FMT_S16
 } audfmt_e;
 
+#ifdef WORDS_BIGENDIAN
+#define AUDIO_HOST_ENDIANNESS 1
+#else
+#define AUDIO_HOST_ENDIANNESS 0
+#endif
+
 typedef struct {
     int freq;
     int nchannels;
     audfmt_e fmt;
+    int endianness;
 } audsettings_t;
+
+typedef enum {
+    AUD_CNOTIFY_ENABLE,
+    AUD_CNOTIFY_DISABLE
+} audcnotification_e;
+
+struct audio_capture_ops {
+    void (*notify) (void *opaque, audcnotification_e cmd);
+    void (*capture) (void *opaque, void *buf, int size);
+    void (*destroy) (void *opaque);
+};
+
+struct capture_ops {
+    void (*info) (void *opaque);
+    void (*destroy) (void *opaque);
+};
+
+typedef struct CaptureState {
+    void *opaque;
+    struct capture_ops ops;
+    LIST_ENTRY (CaptureState) entries;
+} CaptureState;
 
 typedef struct AudioState AudioState;
 typedef struct SWVoiceOut SWVoiceOut;
+typedef struct CaptureVoiceOut CaptureVoiceOut;
 typedef struct SWVoiceIn SWVoiceIn;
 
 typedef struct QEMUSoundCard {
@@ -66,6 +97,13 @@ void AUD_help (void);
 void AUD_help (void);
 void AUD_register_card (AudioState *s, const char *name, QEMUSoundCard *card);
 void AUD_remove_card (QEMUSoundCard *card);
+CaptureVoiceOut *AUD_add_capture (
+    AudioState *s,
+    audsettings_t *as,
+    struct audio_capture_ops *ops,
+    void *opaque
+    );
+void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque);
 
 SWVoiceOut *AUD_open_out (
     QEMUSoundCard *card,
@@ -73,8 +111,7 @@ SWVoiceOut *AUD_open_out (
     const char *name,
     void *callback_opaque,
     audio_callback_fn_t callback_fn,
-    audsettings_t *settings,
-    int sw_endian
+    audsettings_t *settings
     );
 
 void AUD_close_out (QEMUSoundCard *card, SWVoiceOut *sw);
@@ -92,8 +129,7 @@ SWVoiceIn *AUD_open_in (
     const char *name,
     void *callback_opaque,
     audio_callback_fn_t callback_fn,
-    audsettings_t *settings,
-    int sw_endian
+    audsettings_t *settings
     );
 
 void AUD_close_in (QEMUSoundCard *card, SWVoiceIn *sw);
@@ -111,7 +147,7 @@ static inline void *advance (void *p, in
 }
 
 uint32_t popcount (uint32_t u);
-inline uint32_t lsbindex (uint32_t u);
+uint32_t lsbindex (uint32_t u);
 
 #ifdef __GNUC__
 #define audio_MIN(a, b) ( __extension__ ({      \
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/audio/audio_int.h
--- a/tools/ioemu/audio/audio_int.h     Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/audio/audio_int.h     Mon Aug 07 18:25:30 2006 +0100
@@ -61,13 +61,14 @@ struct audio_pcm_info {
     int align;
     int shift;
     int bytes_per_second;
-    int swap_endian;
-};
+    int swap_endianness;
+};
+
+typedef struct SWVoiceCap SWVoiceCap;
 
 typedef struct HWVoiceOut {
     int enabled;
     int pending_disable;
-    int valid;
     struct audio_pcm_info info;
 
     f_sample *clip;
@@ -79,6 +80,7 @@ typedef struct HWVoiceOut {
 
     int samples;
     LIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head;
+    LIST_HEAD (sw_cap_listhead, SWVoiceCap) cap_head;
     struct audio_pcm_ops *pcm_ops;
     LIST_ENTRY (HWVoiceOut) entries;
 } HWVoiceOut;
@@ -160,14 +162,34 @@ struct audio_pcm_ops {
     int  (*ctl_in)  (HWVoiceIn *hw, int cmd, ...);
 };
 
+struct capture_callback {
+    struct audio_capture_ops ops;
+    void *opaque;
+    LIST_ENTRY (capture_callback) entries;
+};
+
+struct CaptureVoiceOut {
+    HWVoiceOut hw;
+    void *buf;
+    LIST_HEAD (cb_listhead, capture_callback) cb_head;
+    LIST_ENTRY (CaptureVoiceOut) entries;
+};
+
+struct SWVoiceCap {
+    SWVoiceOut sw;
+    CaptureVoiceOut *cap;
+    LIST_ENTRY (SWVoiceCap) entries;
+};
+
 struct AudioState {
     struct audio_driver *drv;
     void *drv_opaque;
 
     QEMUTimer *ts;
-    LIST_HEAD (card_head, QEMUSoundCard) card_head;
+    LIST_HEAD (card_listhead, QEMUSoundCard) card_head;
     LIST_HEAD (hw_in_listhead, HWVoiceIn) hw_head_in;
     LIST_HEAD (hw_out_listhead, HWVoiceOut) hw_head_out;
+    LIST_HEAD (cap_listhead, CaptureVoiceOut) cap_head;
     int nb_hw_voices_out;
     int nb_hw_voices_in;
 };
@@ -182,8 +204,7 @@ extern struct audio_driver dsound_audio_
 extern struct audio_driver dsound_audio_driver;
 extern volume_t nominal_volume;
 
-void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as,
-                          int swap_endian);
+void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as);
 void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int 
len);
 
 int  audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int len);
@@ -202,15 +223,6 @@ static inline int audio_ring_dist (int d
 static inline int audio_ring_dist (int dst, int src, int len)
 {
     return (dst >= src) ? (dst - src) : (len - src + dst);
-}
-
-static inline int audio_need_to_swap_endian (int endianness)
-{
-#ifdef WORDS_BIGENDIAN
-    return endianness != 1;
-#else
-    return endianness != 0;
-#endif
 }
 
 #if defined __GNUC__
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/audio/audio_template.h
--- a/tools/ioemu/audio/audio_template.h        Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/audio/audio_template.h        Mon Aug 07 18:25:30 2006 +0100
@@ -140,13 +140,12 @@ static int glue (audio_pcm_sw_init_, TYP
     SW *sw,
     HW *hw,
     const char *name,
-    audsettings_t *as,
-    int endian
+    audsettings_t *as
     )
 {
     int err;
 
-    audio_pcm_init_info (&sw->info, as, audio_need_to_swap_endian (endian));
+    audio_pcm_init_info (&sw->info, as);
     sw->hw = hw;
     sw->active = 0;
 #ifdef DAC
@@ -164,7 +163,7 @@ static int glue (audio_pcm_sw_init_, TYP
 #endif
         [sw->info.nchannels == 2]
         [sw->info.sign]
-        [sw->info.swap_endian]
+        [sw->info.swap_endianness]
         [sw->info.bits == 16];
 
     sw->name = qemu_strdup (name);
@@ -200,6 +199,9 @@ static void glue (audio_pcm_hw_gc_, TYPE
     HW *hw = *hwp;
 
     if (!hw->sw_head.lh_first) {
+#ifdef DAC
+        audio_detach_capture (hw);
+#endif
         LIST_REMOVE (hw, entries);
         glue (s->nb_hw_voices_, TYPE) += 1;
         glue (audio_pcm_hw_free_resources_ ,TYPE) (hw);
@@ -266,7 +268,9 @@ static HW *glue (audio_pcm_hw_add_new_, 
 
     hw->pcm_ops = drv->pcm_ops;
     LIST_INIT (&hw->sw_head);
-
+#ifdef DAC
+    LIST_INIT (&hw->cap_head);
+#endif
     if (glue (hw->pcm_ops->init_, TYPE) (hw, as)) {
         goto err0;
     }
@@ -283,7 +287,7 @@ static HW *glue (audio_pcm_hw_add_new_, 
 #endif
         [hw->info.nchannels == 2]
         [hw->info.sign]
-        [hw->info.swap_endian]
+        [hw->info.swap_endianness]
         [hw->info.bits == 16];
 
     if (glue (audio_pcm_hw_alloc_resources_, TYPE) (hw)) {
@@ -292,6 +296,9 @@ static HW *glue (audio_pcm_hw_add_new_, 
 
     LIST_INSERT_HEAD (&s->glue (hw_head_, TYPE), hw, entries);
     glue (s->nb_hw_voices_, TYPE) -= 1;
+#ifdef DAC
+    audio_attach_capture (s, hw);
+#endif
     return hw;
 
  err1:
@@ -328,8 +335,7 @@ static SW *glue (audio_pcm_create_voice_
 static SW *glue (audio_pcm_create_voice_pair_, TYPE) (
     AudioState *s,
     const char *sw_name,
-    audsettings_t *as,
-    int sw_endian
+    audsettings_t *as
     )
 {
     SW *sw;
@@ -357,7 +363,7 @@ static SW *glue (audio_pcm_create_voice_
 
     glue (audio_pcm_hw_add_sw_, TYPE) (hw, sw);
 
-    if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, sw_name, as, sw_endian)) {
+    if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, sw_name, as)) {
         goto err3;
     }
 
@@ -399,8 +405,7 @@ SW *glue (AUD_open_, TYPE) (
     const char *name,
     void *callback_opaque ,
     audio_callback_fn_t callback_fn,
-    audsettings_t *as,
-    int sw_endian
+    audsettings_t *as
     )
 {
     AudioState *s;
@@ -421,7 +426,7 @@ SW *glue (AUD_open_, TYPE) (
 
     s = card->audio;
 
-    if (audio_bug (AUDIO_FUNC, audio_validate_settigs (as))) {
+    if (audio_bug (AUDIO_FUNC, audio_validate_settings (as))) {
         audio_print_settings (as);
         goto fail;
     }
@@ -473,12 +478,12 @@ SW *glue (AUD_open_, TYPE) (
         }
 
         glue (audio_pcm_sw_fini_, TYPE) (sw);
-        if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, name, as, sw_endian)) {
+        if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, name, as)) {
             goto fail;
         }
     }
     else {
-        sw = glue (audio_pcm_create_voice_pair_, TYPE) (s, name, as, 
sw_endian);
+        sw = glue (audio_pcm_create_voice_pair_, TYPE) (s, name, as);
         if (!sw) {
             dolog ("Failed to create voice `%s'\n", name);
             return NULL;
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/audio/coreaudio.c
--- a/tools/ioemu/audio/coreaudio.c     Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/audio/coreaudio.c     Mon Aug 07 18:25:30 2006 +0100
@@ -275,8 +275,6 @@ static OSStatus audioDeviceIOProc(
 #endif
     }
 
-    /* cleanup */
-    mixeng_clear (src, frameCount);
     rpos = (rpos + frameCount) % hw->samples;
     core->decr += frameCount;
     core->rpos = rpos;
@@ -297,7 +295,6 @@ static int coreaudio_init_out (HWVoiceOu
     UInt32 propertySize;
     int err;
     int bits = 8;
-    int endianess = 0;
     const char *typ = "playback";
     AudioValueRange frameRange;
 
@@ -310,16 +307,9 @@ static int coreaudio_init_out (HWVoiceOu
 
     if (as->fmt == AUD_FMT_S16 || as->fmt == AUD_FMT_U16) {
         bits = 16;
-        endianess = 1;
-    }
-
-    audio_pcm_init_info (
-        &hw->info,
-        as,
-        /* Following is irrelevant actually since we do not use
-           mixengs clipping routines */
-        audio_need_to_swap_endian (endianess)
-        );
+    }
+
+    audio_pcm_init_info (&hw->info, as);
 
     /* open default output device */
     propertySize = sizeof(core->outputDeviceID);
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/audio/dsound_template.h
--- a/tools/ioemu/audio/dsound_template.h       Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/audio/dsound_template.h       Mon Aug 07 18:25:30 2006 +0100
@@ -70,7 +70,13 @@ static int glue (dsound_lock_, TYPE) (
     int i;
     LPVOID p1 = NULL, p2 = NULL;
     DWORD blen1 = 0, blen2 = 0;
-
+    DWORD flag;
+
+#ifdef DSBTYPE_IN
+    flag = entire ? DSCBLOCK_ENTIREBUFFER : 0;
+#else
+    flag = entire ? DSBLOCK_ENTIREBUFFER : 0;
+#endif
     for (i = 0; i < conf.lock_retries; ++i) {
         hr = glue (IFACE, _Lock) (
             buf,
@@ -80,13 +86,7 @@ static int glue (dsound_lock_, TYPE) (
             &blen1,
             &p2,
             &blen2,
-            (entire
-#ifdef DSBTYPE_IN
-             ? DSCBLOCK_ENTIREBUFFER
-#else
-             ? DSBLOCK_ENTIREBUFFER
-#endif
-             : 0)
+            flag
             );
 
         if (FAILED (hr)) {
@@ -250,8 +250,8 @@ static int dsound_init_out (HWVoiceOut *
     }
 
     ds->first_time = 1;
-
-    audio_pcm_init_info (&hw->info, &obt_as, audio_need_to_swap_endian (0));
+    obt_as.endianness = 0;
+    audio_pcm_init_info (&hw->info, &obt_as);
 
     if (bc.dwBufferBytes & hw->info.align) {
         dolog (
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/audio/dsoundaudio.c
--- a/tools/ioemu/audio/dsoundaudio.c   Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/audio/dsoundaudio.c   Mon Aug 07 18:25:30 2006 +0100
@@ -453,13 +453,11 @@ static void dsound_write_sample (HWVoice
 
     if (src_len1) {
         hw->clip (dst, src1, src_len1);
-        mixeng_clear (src1, src_len1);
     }
 
     if (src_len2) {
         dst = advance (dst, src_len1 << hw->info.shift);
         hw->clip (dst, src2, src_len2);
-        mixeng_clear (src2, src_len2);
     }
 
     hw->rpos = pos % hw->samples;
@@ -987,6 +985,12 @@ static void *dsound_audio_init (void)
     hr = IDirectSound_Initialize (s->dsound, NULL);
     if (FAILED (hr)) {
         dsound_logerr (hr, "Could not initialize DirectSound\n");
+
+        hr = IDirectSound_Release (s->dsound);
+        if (FAILED (hr)) {
+            dsound_logerr (hr, "Could not release DirectSound\n");
+        }
+        s->dsound = NULL;
         return NULL;
     }
 
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/audio/fmodaudio.c
--- a/tools/ioemu/audio/fmodaudio.c     Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/audio/fmodaudio.c     Mon Aug 07 18:25:30 2006 +0100
@@ -153,13 +153,11 @@ static void fmod_write_sample (HWVoiceOu
 
     if (src_len1) {
         hw->clip (dst, src1, src_len1);
-        mixeng_clear (src1, src_len1);
     }
 
     if (src_len2) {
         dst = advance (dst, src_len1 << hw->info.shift);
         hw->clip (dst, src2, src_len2);
-        mixeng_clear (src2, src_len2);
     }
 
     hw->rpos = pos % hw->samples;
@@ -360,6 +358,7 @@ static int fmod_init_out (HWVoiceOut *hw
 {
     int bits16, mode, channel;
     FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
+    audsettings_t obt_as = *as;
 
     mode = aud_to_fmodfmt (as->fmt, as->nchannels == 2 ? 1 : 0);
     fmd->fmod_sample = FSOUND_Sample_Alloc (
@@ -386,7 +385,8 @@ static int fmod_init_out (HWVoiceOut *hw
     fmd->channel = channel;
 
     /* FMOD always operates on little endian frames? */
-    audio_pcm_init_info (&hw->info, as, audio_need_to_swap_endian (0));
+    obt_as.endianness = 0;
+    audio_pcm_init_info (&hw->info, &obt_as);
     bits16 = (mode & FSOUND_16BITS) != 0;
     hw->samples = conf.nb_samples;
     return 0;
@@ -420,6 +420,7 @@ static int fmod_init_in (HWVoiceIn *hw, 
 {
     int bits16, mode;
     FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
+    audsettings_t obt_as = *as;
 
     if (conf.broken_adc) {
         return -1;
@@ -442,7 +443,8 @@ static int fmod_init_in (HWVoiceIn *hw, 
     }
 
     /* FMOD always operates on little endian frames? */
-    audio_pcm_init_info (&hw->info, as, audio_need_to_swap_endian (0));
+    obt_as.endianness = 0;
+    audio_pcm_init_info (&hw->info, &obt_as);
     bits16 = (mode & FSOUND_16BITS) != 0;
     hw->samples = conf.nb_samples;
     return 0;
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/audio/noaudio.c
--- a/tools/ioemu/audio/noaudio.c       Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/audio/noaudio.c       Mon Aug 07 18:25:30 2006 +0100
@@ -40,21 +40,20 @@ static int no_run_out (HWVoiceOut *hw)
 {
     NoVoiceOut *no = (NoVoiceOut *) hw;
     int live, decr, samples;
-    int64_t now = qemu_get_clock (vm_clock);
-    int64_t ticks = now - no->old_ticks;
-    int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec;
-
-    if (bytes > INT_MAX) {
-        samples = INT_MAX >> hw->info.shift;
-    }
-    else {
-        samples = bytes >> hw->info.shift;
-    }
+    int64_t now;
+    int64_t ticks;
+    int64_t bytes;
 
     live = audio_pcm_hw_get_live_out (&no->hw);
     if (!live) {
         return 0;
     }
+
+    now = qemu_get_clock (vm_clock);
+    ticks = now - no->old_ticks;
+    bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec;
+    bytes = audio_MIN (bytes, INT_MAX);
+    samples = bytes >> hw->info.shift;
 
     no->old_ticks = now;
     decr = audio_MIN (live, samples);
@@ -69,7 +68,7 @@ static int no_write (SWVoiceOut *sw, voi
 
 static int no_init_out (HWVoiceOut *hw, audsettings_t *as)
 {
-    audio_pcm_init_info (&hw->info, as, 0);
+    audio_pcm_init_info (&hw->info, as);
     hw->samples = 1024;
     return 0;
 }
@@ -88,7 +87,7 @@ static int no_ctl_out (HWVoiceOut *hw, i
 
 static int no_init_in (HWVoiceIn *hw, audsettings_t *as)
 {
-    audio_pcm_init_info (&hw->info, as, 0);
+    audio_pcm_init_info (&hw->info, as);
     hw->samples = 1024;
     return 0;
 }
@@ -101,17 +100,20 @@ static int no_run_in (HWVoiceIn *hw)
 static int no_run_in (HWVoiceIn *hw)
 {
     NoVoiceIn *no = (NoVoiceIn *) hw;
-    int64_t now = qemu_get_clock (vm_clock);
-    int64_t ticks = now - no->old_ticks;
-    int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec;
     int live = audio_pcm_hw_get_live_in (hw);
     int dead = hw->samples - live;
-    int samples;
+    int samples = 0;
 
-    bytes = audio_MIN (bytes, INT_MAX);
-    samples = bytes >> hw->info.shift;
-    samples = audio_MIN (samples, dead);
+    if (dead) {
+        int64_t now = qemu_get_clock (vm_clock);
+        int64_t ticks = now - no->old_ticks;
+        int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec;
 
+        no->old_ticks = now;
+        bytes = audio_MIN (bytes, INT_MAX);
+        samples = bytes >> hw->info.shift;
+        samples = audio_MIN (samples, dead);
+    }
     return samples;
 }
 
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/audio/ossaudio.c
--- a/tools/ioemu/audio/ossaudio.c      Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/audio/ossaudio.c      Mon Aug 07 18:25:30 2006 +0100
@@ -55,12 +55,14 @@ static struct {
     int fragsize;
     const char *devpath_out;
     const char *devpath_in;
+    int debug;
 } conf = {
     .try_mmap = 0,
     .nfrags = 4,
     .fragsize = 4096,
     .devpath_out = "/dev/dsp",
-    .devpath_in = "/dev/dsp"
+    .devpath_in = "/dev/dsp",
+    .debug = 0
 };
 
 struct oss_params {
@@ -324,9 +326,20 @@ static int oss_run_out (HWVoiceOut *hw)
             return 0;
         }
 
-        if (abinfo.bytes < 0 || abinfo.bytes > bufsize) {
-            ldebug ("warning: Invalid available size, size=%d bufsize=%d\n",
-                    abinfo.bytes, bufsize);
+        if (abinfo.bytes > bufsize) {
+            if (conf.debug) {
+                dolog ("warning: Invalid available size, size=%d bufsize=%d\n"
+                       "please report your OS/audio hw to 
malc@xxxxxxxxxxxxx\n",
+                       abinfo.bytes, bufsize);
+            }
+            abinfo.bytes = bufsize;
+        }
+
+        if (abinfo.bytes < 0) {
+            if (conf.debug) {
+                dolog ("warning: Invalid available size, size=%d bufsize=%d\n",
+                       abinfo.bytes, bufsize);
+            }
             return 0;
         }
 
@@ -369,14 +382,11 @@ static int oss_run_out (HWVoiceOut *hw)
                            "alignment %d\n",
                            wbytes, written, hw->info.align + 1);
                 }
-                mixeng_clear (src, wsamples);
                 decr -= wsamples;
                 rpos = (rpos + wsamples) % hw->samples;
                 break;
             }
         }
-
-        mixeng_clear (src, convert_samples);
 
         rpos = (rpos + convert_samples) % hw->samples;
         samples -= convert_samples;
@@ -443,12 +453,9 @@ static int oss_init_out (HWVoiceOut *hw,
     obt_as.freq = obt.freq;
     obt_as.nchannels = obt.nchannels;
     obt_as.fmt = effective_fmt;
-
-    audio_pcm_init_info (
-        &hw->info,
-        &obt_as,
-        audio_need_to_swap_endian (endianness)
-        );
+    obt_as.endianness = endianness;
+
+    audio_pcm_init_info (&hw->info, &obt_as);
     oss->nfrags = obt.nfrags;
     oss->fragsize = obt.fragsize;
 
@@ -587,12 +594,9 @@ static int oss_init_in (HWVoiceIn *hw, a
     obt_as.freq = obt.freq;
     obt_as.nchannels = obt.nchannels;
     obt_as.fmt = effective_fmt;
-
-    audio_pcm_init_info (
-        &hw->info,
-        &obt_as,
-        audio_need_to_swap_endian (endianness)
-        );
+    obt_as.endianness = endianness;
+
+    audio_pcm_init_info (&hw->info, &obt_as);
     oss->nfrags = obt.nfrags;
     oss->fragsize = obt.fragsize;
 
@@ -730,6 +734,8 @@ static struct audio_option oss_options[]
      "Path to DAC device", NULL, 0},
     {"ADC_DEV", AUD_OPT_STR, &conf.devpath_in,
      "Path to ADC device", NULL, 0},
+    {"DEBUG", AUD_OPT_BOOL, &conf.debug,
+     "Turn on some debugging messages", NULL, 0},
     {NULL, 0, NULL, NULL, NULL, 0}
 };
 
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/audio/rate_template.h
--- a/tools/ioemu/audio/rate_template.h Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/audio/rate_template.h Mon Aug 07 18:25:30 2006 +0100
@@ -51,7 +51,7 @@ void NAME (void *opaque, st_sample_t *ib
     if (rate->opos_inc == (1ULL + UINT_MAX)) {
         int i, n = *isamp > *osamp ? *osamp : *isamp;
         for (i = 0; i < n; i++) {
-            OP (obuf[i].l, ibuf[i].r);
+            OP (obuf[i].l, ibuf[i].l);
             OP (obuf[i].r, ibuf[i].r);
         }
         *isamp = n;
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/audio/sdlaudio.c
--- a/tools/ioemu/audio/sdlaudio.c      Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/audio/sdlaudio.c      Mon Aug 07 18:25:30 2006 +0100
@@ -240,7 +240,6 @@ static void sdl_callback (void *opaque, 
 
             /* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */
             hw->clip (buf, src, chunk);
-            mixeng_clear (src, chunk);
             sdl->rpos = (sdl->rpos + chunk) % hw->samples;
             to_mix -= chunk;
             buf += chunk << hw->info.shift;
@@ -336,12 +335,9 @@ static int sdl_init_out (HWVoiceOut *hw,
     obt_as.freq = obt.freq;
     obt_as.nchannels = obt.channels;
     obt_as.fmt = effective_fmt;
-
-    audio_pcm_init_info (
-        &hw->info,
-        &obt_as,
-        audio_need_to_swap_endian (endianess)
-        );
+    obt_as.endianness = endianess;
+
+    audio_pcm_init_info (&hw->info, &obt_as);
     hw->samples = obt.samples;
 
     s->initialized = 1;
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/audio/wavaudio.c
--- a/tools/ioemu/audio/wavaudio.c      Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/audio/wavaudio.c      Mon Aug 07 18:25:30 2006 +0100
@@ -81,7 +81,6 @@ static int wav_run_out (HWVoiceOut *hw)
 
         hw->clip (dst, src, convert_samples);
         qemu_put_buffer (wav->f, dst, convert_samples << hw->info.shift);
-        mixeng_clear (src, convert_samples);
 
         rpos = (rpos + convert_samples) % hw->samples;
         samples -= convert_samples;
@@ -136,7 +135,8 @@ static int wav_init_out (HWVoiceOut *hw,
 
     hdr[34] = bits16 ? 0x10 : 0x08;
 
-    audio_pcm_init_info (&hw->info, &wav_as, audio_need_to_swap_endian (0));
+    wav_as.endianness = 0;
+    audio_pcm_init_info (&hw->info, &wav_as);
 
     hw->samples = 1024;
     wav->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/block-cow.c
--- a/tools/ioemu/block-cow.c   Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/block-cow.c   Mon Aug 07 18:25:30 2006 +0100
@@ -250,6 +250,12 @@ static int cow_create(const char *filena
     return 0;
 }
 
+static void cow_flush(BlockDriverState *bs)
+{
+    BDRVCowState *s = bs->opaque;
+    fsync(s->fd);
+}
+
 BlockDriver bdrv_cow = {
     "cow",
     sizeof(BDRVCowState),
@@ -259,6 +265,7 @@ BlockDriver bdrv_cow = {
     cow_write,
     cow_close,
     cow_create,
+    cow_flush,
     cow_is_allocated,
 };
 #endif
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/block-qcow.c
--- a/tools/ioemu/block-qcow.c  Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/block-qcow.c  Mon Aug 07 18:25:30 2006 +0100
@@ -693,6 +693,12 @@ int qcow_compress_cluster(BlockDriverSta
     return 0;
 }
 
+static void qcow_flush(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+    fsync(s->fd);
+}
+
 BlockDriver bdrv_qcow = {
     "qcow",
     sizeof(BDRVQcowState),
@@ -702,6 +708,7 @@ BlockDriver bdrv_qcow = {
     qcow_write,
     qcow_close,
     qcow_create,
+    qcow_flush,
     qcow_is_allocated,
     qcow_set_key,
     qcow_make_empty
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/block-vmdk.c
--- a/tools/ioemu/block-vmdk.c  Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/block-vmdk.c  Mon Aug 07 18:25:30 2006 +0100
@@ -426,6 +426,12 @@ static void vmdk_close(BlockDriverState 
     close(s->fd);
 }
 
+static void vmdk_flush(BlockDriverState *bs)
+{
+    BDRVVmdkState *s = bs->opaque;
+    fsync(s->fd);
+}
+
 BlockDriver bdrv_vmdk = {
     "vmdk",
     sizeof(BDRVVmdkState),
@@ -435,5 +441,6 @@ BlockDriver bdrv_vmdk = {
     vmdk_write,
     vmdk_close,
     vmdk_create,
+    vmdk_flush,
     vmdk_is_allocated,
 };
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/block-vpc.c
--- a/tools/ioemu/block-vpc.c   Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/block-vpc.c   Mon Aug 07 18:25:30 2006 +0100
@@ -163,7 +163,7 @@ static inline int seek_to_sector(BlockDr
     bitmap_offset = 512 * s->pagetable[pagetable_index];
     block_offset = bitmap_offset + 512 + (512 * pageentry_index);
     
-//    printf("sector: %llx, index: %x, offset: %x, bioff: %llx, bloff: %llx\n",
+//    printf("sector: %" PRIx64 ", index: %x, offset: %x, bioff: %" PRIx64 ", 
bloff: %" PRIx64 "\n",
 //     sector_num, pagetable_index, pageentry_index,
 //     bitmap_offset, block_offset);
 
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/block-vvfat.c
--- a/tools/ioemu/block-vvfat.c Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/block-vvfat.c Mon Aug 07 18:25:30 2006 +0100
@@ -2772,6 +2772,7 @@ BlockDriver bdrv_vvfat = {
     vvfat_read,
     vvfat_write,
     vvfat_close,
+    NULL, /* ??? Not sure if we can do any meaningful flushing.  */
     NULL,
     vvfat_is_allocated
 };
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/block.c
--- a/tools/ioemu/block.c       Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/block.c       Mon Aug 07 18:25:30 2006 +0100
@@ -615,6 +615,14 @@ const char *bdrv_get_device_name(BlockDr
     return bs->device_name;
 }
 
+void bdrv_flush(BlockDriverState *bs)
+{
+    if (bs->drv->bdrv_flush)
+        bs->drv->bdrv_flush(bs);
+    if (bs->backing_hd)
+        bdrv_flush(bs->backing_hd);
+}
+
 void bdrv_info(void)
 {
     BlockDriverState *bs;
@@ -754,6 +762,51 @@ static void raw_close(BlockDriverState *
     close(s->fd);
 }
 
+#ifdef _WIN32
+#include <windows.h>
+#include <winioctl.h>
+
+int qemu_ftruncate64(int fd, int64_t length)
+{
+    LARGE_INTEGER li;
+    LONG high;
+    HANDLE h;
+    BOOL res;
+
+    if ((GetVersion() & 0x80000000UL) && (length >> 32) != 0)
+       return -1;
+
+    h = (HANDLE)_get_osfhandle(fd);
+
+    /* get current position, ftruncate do not change position */
+    li.HighPart = 0;
+    li.LowPart = SetFilePointer (h, 0, &li.HighPart, FILE_CURRENT);
+    if (li.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
+       return -1;
+
+    high = length >> 32;
+    if (!SetFilePointer(h, (DWORD) length, &high, FILE_BEGIN))
+       return -1;
+    res = SetEndOfFile(h);
+
+    /* back to old position */
+    SetFilePointer(h, li.LowPart, &li.HighPart, FILE_BEGIN);
+    return res ? 0 : -1;
+}
+
+static int set_sparse(int fd)
+{
+    DWORD returned;
+    return (int) DeviceIoControl((HANDLE)_get_osfhandle(fd), FSCTL_SET_SPARSE,
+                                NULL, 0, NULL, 0, &returned, NULL);
+}
+#else
+static inline int set_sparse(int fd)
+{
+    return 1;
+}
+#endif
+
 static int raw_create(const char *filename, int64_t total_size,
                       const char *backing_file, int flags)
 {
@@ -766,9 +819,16 @@ static int raw_create(const char *filena
               0644);
     if (fd < 0)
         return -EIO;
+    set_sparse(fd);
     ftruncate(fd, total_size * 512);
     close(fd);
     return 0;
+}
+
+static void raw_flush(BlockDriverState *bs)
+{
+    BDRVRawState *s = bs->opaque;
+    fsync(s->fd);
 }
 
 BlockDriver bdrv_raw = {
@@ -780,6 +840,7 @@ BlockDriver bdrv_raw = {
     raw_write,
     raw_close,
     raw_create,
+    raw_flush,
 };
 
 void bdrv_init(void)
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/block_int.h
--- a/tools/ioemu/block_int.h   Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/block_int.h   Mon Aug 07 18:25:30 2006 +0100
@@ -36,6 +36,7 @@ struct BlockDriver {
     void (*bdrv_close)(BlockDriverState *bs);
     int (*bdrv_create)(const char *filename, int64_t total_sectors, 
                        const char *backing_file, int flags);
+    void (*bdrv_flush)(BlockDriverState *bs);
     int (*bdrv_is_allocated)(BlockDriverState *bs, int64_t sector_num,
                              int nb_sectors, int *pnum);
     int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/cocoa.m
--- a/tools/ioemu/cocoa.m       Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/cocoa.m       Mon Aug 07 18:25:30 2006 +0100
@@ -439,23 +439,40 @@ static void cocoa_refresh(DisplayState *
                                 kbd_put_keycode(keycode & 0x7f); //remove e0 
bit in front
                             /* handle monitor key events */
                             } else {
+                                int keysym = 0;
+
                                 switch([event keyCode]) {
-                                    case 123:
-                                        kbd_put_keysym(QEMU_KEY_LEFT);
-                                        break;
-                                    case 124:
-                                        kbd_put_keysym(QEMU_KEY_RIGHT);
-                                        break;
-                                    case 125:
-                                        kbd_put_keysym(QEMU_KEY_DOWN);
-                                        break;
-                                    case 126:
-                                        kbd_put_keysym(QEMU_KEY_UP);
-                                        break;
-                                    default:
-                                        kbd_put_keysym([[event characters] 
characterAtIndex:0]);
-                                        break;
+                                case 115:
+                                    keysym = QEMU_KEY_HOME;
+                                    break;
+                                case 117:
+                                    keysym = QEMU_KEY_DELETE;
+                                    break;
+                                case 119:
+                                    keysym = QEMU_KEY_END;
+                                    break;
+                                case 123:
+                                    keysym = QEMU_KEY_LEFT;
+                                    break;
+                                case 124:
+                                    keysym = QEMU_KEY_RIGHT;
+                                    break;
+                                case 125:
+                                    keysym = QEMU_KEY_DOWN;
+                                    break;
+                                case 126:
+                                    keysym = QEMU_KEY_UP;
+                                    break;
+                                default:
+                                    {
+                                        NSString *ks = [event characters];
+
+                                        if ([ks length] > 0)
+                                            keysym = [ks characterAtIndex:0];
+                                    }
                                 }
+                                if (keysym)
+                                    kbd_put_keysym(keysym);
                             }
                         }
                     }
@@ -867,10 +884,9 @@ static void setupWindowMenu(void)
     /* Finally give up our references to the objects */
     [windowMenu release];
     [windowMenuItem release];
- 
-}
-
-static void CustomApplicationMain (argc, argv)
+}
+
+static void CustomApplicationMain(void)
 {
     NSAutoreleasePool   *pool = [[NSAutoreleasePool alloc] init];
     QemuCocoaGUIController *gui_controller;
@@ -904,8 +920,8 @@ int main(int argc, char **argv)
 {
     gArgc = argc;
     gArgv = argv;
-    
-    CustomApplicationMain (argc, argv);
-    
+
+    CustomApplicationMain();
+
     return 0;
 }
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/configure
--- a/tools/ioemu/configure     Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/configure     Mon Aug 07 18:25:30 2006 +0100
@@ -96,6 +96,8 @@ softmmu="yes"
 softmmu="yes"
 user="no"
 build_docs="no"
+build_acpi_tables="no"
+uname_release=""
 
 # OS specific
 targetos=`uname -s`
@@ -212,7 +214,7 @@ for opt do
   ;;
   --fmod-inc=*) fmod_inc="$optarg"
   ;;
-  --enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-"
+  --enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-" ; user="no"
   ;;
   --disable-slirp) slirp="no"
   ;;
@@ -235,6 +237,10 @@ for opt do
   --disable-user) user="no"
   ;;
   --enable-user) user="yes"
+  ;;
+  --enable-uname-release=*) uname_release="$optarg"
+  ;;
+  --enable-iasl) build_acpi_tables="yes"
   ;;
   esac
 done
@@ -283,6 +289,8 @@ echo "  --disable-user           disable
 echo "  --disable-user           disable all linux usermode emulation targets"
 echo "  --fmod-lib               path to FMOD library"
 echo "  --fmod-inc               path to FMOD includes"
+echo "  --enable-uname-release=R Return R for uname -r in usermode emulation"
+echo "  --enable-iasl            compilation of ACPI tables with the IASL 
compiler"
 echo ""
 echo "NOTE: The object files are build at the place where configure is 
launched"
 exit 1
@@ -292,15 +300,21 @@ ar="${cross_prefix}${ar}"
 ar="${cross_prefix}${ar}"
 strip="${cross_prefix}${strip}"
 
-if [ ! -x "`which $cc`" ] ; then
-    echo "Compiler $cc could not be found"
-    exit
+# check that the C compiler works.
+cat > $TMPC <<EOF
+int main(void) {}
+EOF
+
+if $cc -c -o $TMPO $TMPC 2>/dev/null ; then
+  : C compiler works ok
+else
+    echo "ERROR: \"$cc\" either does not exist or does not work"
+    exit 1
 fi
 
 if test "$mingw32" = "yes" ; then
     linux="no"
     EXESUF=".exe"
-    gdbstub="no"
     oss="no"
     if [ "$cpu" = "i386" ] ; then
         kqemu="yes"
@@ -551,6 +565,8 @@ echo "FMOD support      $fmod $fmod_supp
 echo "FMOD support      $fmod $fmod_support"
 echo "kqemu support     $kqemu"
 echo "Documentation     $build_docs"
+[ ! -z "$uname_release" ] && \
+echo "uname -r          $uname_release"
 
 if test $sdl_too_old = "yes"; then
 echo "-> Your SDL version is too old - please upgrade to have SDL support"
@@ -703,6 +719,9 @@ if [ "$build_docs" = "yes" ] ; then
 if [ "$build_docs" = "yes" ] ; then
   echo "BUILD_DOCS=yes" >> $config_mak
 fi
+if [ "$build_acpi_tables" = "yes" ] ; then
+  echo "BUILD_ACPI_TABLES=yes" >> $config_mak
+fi
 
 # XXX: suppress that
 if [ "$bsd" = "yes" ] ; then
@@ -710,6 +729,8 @@ if [ "$bsd" = "yes" ] ; then
   echo "#define MAP_ANONYMOUS MAP_ANON" >> $config_h
   echo "#define _BSD 1" >> $config_h
 fi
+
+echo "#define CONFIG_UNAME_RELEASE \"$uname_release\"" >> $config_h
 
 for target in $target_list; do
 target_dir="$target"
@@ -723,6 +744,7 @@ target_bigendian="no"
 [ "$target_cpu" = "ppc" ] && target_bigendian=yes
 [ "$target_cpu" = "ppc64" ] && target_bigendian=yes
 [ "$target_cpu" = "mips" ] && target_bigendian=yes
+[ "$target_cpu" = "sh4eb" ] && target_bigendian=yes
 target_softmmu="no"
 if expr $target : '.*-softmmu' > /dev/null ; then
   target_softmmu="yes"
@@ -759,6 +781,7 @@ echo "include ../config-host.mak" >> $co
 echo "include ../config-host.mak" >> $config_mak
 echo "#include \"../config-host.h\"" >> $config_h
 
+bflt="no"
 interp_prefix1=`echo "$interp_prefix" | sed "s/%M/$target_cpu/g"`
 echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix1\"" >> $config_h
 
@@ -779,6 +802,7 @@ elif test "$target_cpu" = "arm" -o "$tar
   echo "TARGET_ARCH=arm" >> $config_mak
   echo "#define TARGET_ARCH \"arm\"" >> $config_h
   echo "#define TARGET_ARM 1" >> $config_h
+  bflt="yes"
 elif test "$target_cpu" = "sparc" ; then
   echo "TARGET_ARCH=sparc" >> $config_mak
   echo "#define TARGET_ARCH \"sparc\"" >> $config_h
@@ -809,10 +833,13 @@ elif test "$target_cpu" = "mips" -o "$ta
   echo "TARGET_ARCH=mips" >> $config_mak
   echo "#define TARGET_ARCH \"mips\"" >> $config_h
   echo "#define TARGET_MIPS 1" >> $config_h
-elif test "$target_cpu" = "sh4" ; then
+  echo "CONFIG_SOFTFLOAT=yes" >> $config_mak
+  echo "#define CONFIG_SOFTFLOAT 1" >> $config_h
+elif test "$target_cpu" = "sh4" -o "$target_cpu" = "sh4eb" ; then
   echo "TARGET_ARCH=sh4" >> $config_mak
   echo "#define TARGET_ARCH \"sh4\"" >> $config_h
   echo "#define TARGET_SH4 1" >> $config_h
+  bflt="yes"
 else
   echo "Unsupported target CPU"
   exit 1
@@ -834,9 +861,13 @@ if expr $target : '.*-dm' > /dev/null ; 
   echo "#define CONFIG_DM 1" >> $config_h
 fi
 
-if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" ; then
+if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" -o "$target_cpu" = 
"sparc" -o "$target_cpu" = "sparc64"; then
   echo "CONFIG_SOFTFLOAT=yes" >> $config_mak
   echo "#define CONFIG_SOFTFLOAT 1" >> $config_h
+fi
+if test "$target_user_only" = "yes" -a "$bflt" = "yes"; then
+  echo "TARGET_HAS_BFLT=yes" >> $config_mak
+  echo "#define TARGET_HAS_BFLT 1" >> $config_h
 fi
 # sdl defines
 
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/console.c
--- a/tools/ioemu/console.c     Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/console.c     Mon Aug 07 18:25:30 2006 +0100
@@ -27,8 +27,8 @@
 #define DEFAULT_BACKSCROLL 512
 #define MAX_CONSOLES 12
 
-#define RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
-#define RGB(r, g, b) RGBA(r, g, b, 0xff)
+#define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
+#define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff)
 
 typedef struct TextAttributes {
     uint8_t fgcol:4;
@@ -52,6 +52,57 @@ enum TTYState {
     TTY_STATE_ESC,
     TTY_STATE_CSI,
 };
+
+typedef struct QEMUFIFO {
+    uint8_t *buf;
+    int buf_size;
+    int count, wptr, rptr;
+} QEMUFIFO;
+
+int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
+{
+    int l, len;
+
+    l = f->buf_size - f->count;
+    if (len1 > l)
+        len1 = l;
+    len = len1;
+    while (len > 0) {
+        l = f->buf_size - f->wptr;
+        if (l > len)
+            l = len;
+        memcpy(f->buf + f->wptr, buf, l);
+        f->wptr += l;
+        if (f->wptr >= f->buf_size)
+            f->wptr = 0;
+        buf += l;
+        len -= l;
+    }
+    f->count += len1;
+    return len1;
+}
+
+int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
+{
+    int l, len;
+
+    if (len1 > f->count)
+        len1 = f->count;
+    len = len1;
+    while (len > 0) {
+        l = f->buf_size - f->rptr;
+        if (l > len)
+            l = len;
+        memcpy(buf, f->buf + f->rptr, l);
+        f->rptr += l;
+        if (f->rptr >= f->buf_size)
+            f->rptr = 0;
+        buf += l;
+        len -= l;
+    }
+    f->count -= len1;
+    return len1;
+}
 
 /* ??? This is mis-named.
    It is used for both text and graphical consoles.  */
@@ -81,8 +132,13 @@ struct TextConsole {
     int nb_esc_params;
 
     /* kbd read handler */
+    IOCanRWHandler *fd_can_read; 
     IOReadHandler *fd_read;
     void *fd_opaque;
+    /* fifo for key pressed */
+    QEMUFIFO out_fifo;
+    uint8_t out_fifo_buf[16];
+    QEMUTimer *kbd_timer;
 };
 
 static TextConsole *active_console;
@@ -274,24 +330,24 @@ enum color_names {
 
 static const uint32_t color_table_rgb[2][8] = {
     {   /* dark */
-        RGB(0x00, 0x00, 0x00),  /* black */
-        RGB(0xaa, 0x00, 0x00),  /* red */
-        RGB(0x00, 0xaa, 0x00),  /* green */
-        RGB(0xaa, 0xaa, 0x00),  /* yellow */
-        RGB(0x00, 0x00, 0xaa),  /* blue */
-        RGB(0xaa, 0x00, 0xaa),  /* magenta */
-        RGB(0x00, 0xaa, 0xaa),  /* cyan */
-        RGB(0xaa, 0xaa, 0xaa),  /* white */
+        QEMU_RGB(0x00, 0x00, 0x00),  /* black */
+        QEMU_RGB(0xaa, 0x00, 0x00),  /* red */
+        QEMU_RGB(0x00, 0xaa, 0x00),  /* green */
+        QEMU_RGB(0xaa, 0xaa, 0x00),  /* yellow */
+        QEMU_RGB(0x00, 0x00, 0xaa),  /* blue */
+        QEMU_RGB(0xaa, 0x00, 0xaa),  /* magenta */
+        QEMU_RGB(0x00, 0xaa, 0xaa),  /* cyan */
+        QEMU_RGB(0xaa, 0xaa, 0xaa),  /* white */
     },
     {   /* bright */
-        RGB(0x00, 0x00, 0x00),  /* black */
-        RGB(0xff, 0x00, 0x00),  /* red */
-        RGB(0x00, 0xff, 0x00),  /* green */
-        RGB(0xff, 0xff, 0x00),  /* yellow */
-        RGB(0x00, 0x00, 0xff),  /* blue */
-        RGB(0xff, 0x00, 0xff),  /* magenta */
-        RGB(0x00, 0xff, 0xff),  /* cyan */
-        RGB(0xff, 0xff, 0xff),  /* white */
+        QEMU_RGB(0x00, 0x00, 0x00),  /* black */
+        QEMU_RGB(0xff, 0x00, 0x00),  /* red */
+        QEMU_RGB(0x00, 0xff, 0x00),  /* green */
+        QEMU_RGB(0xff, 0xff, 0x00),  /* yellow */
+        QEMU_RGB(0x00, 0x00, 0xff),  /* blue */
+        QEMU_RGB(0xff, 0x00, 0xff),  /* magenta */
+        QEMU_RGB(0x00, 0xff, 0xff),  /* cyan */
+        QEMU_RGB(0xff, 0xff, 0xff),  /* white */
     }
 };
 
@@ -563,7 +619,6 @@ static void console_put_lf(TextConsole *
     TextCell *c;
     int x, y1;
 
-    s->x = 0;
     s->y++;
     if (s->y >= s->height) {
         s->y = s->height - 1;
@@ -712,15 +767,12 @@ static void console_putchar(TextConsole 
             console_put_lf(s);
             break;
         case '\b':  /* backspace */
-            if(s->x > 0) s->x--;
-            y1 = (s->y_base + s->y) % s->total_height;
-            c = &s->cells[y1 * s->width + s->x];
-            c->ch = ' ';
-            c->t_attrib = s->t_attrib;
-            update_xy(s, s->x, s->y);
+            if (s->x > 0) 
+                s->x--;
             break;
         case '\t':  /* tabspace */
             if (s->x + (8 - (s->x % 8)) > s->width) {
+                s->x = 0;
                 console_put_lf(s);
             } else {
                 s->x = s->x + (8 - (s->x % 8));
@@ -739,8 +791,10 @@ static void console_putchar(TextConsole 
             c->t_attrib = s->t_attrib;
             update_xy(s, s->x, s->y);
             s->x++;
-            if (s->x >= s->width)
+            if (s->x >= s->width) {
+                s->x = 0;
                 console_put_lf(s);
+            }
             break;
         }
         break;
@@ -835,6 +889,7 @@ static void console_chr_add_read_handler
                                          IOReadHandler *fd_read, void *opaque)
 {
     TextConsole *s = chr->opaque;
+    s->fd_can_read = fd_can_read;
     s->fd_read = fd_read;
     s->fd_opaque = opaque;
 }
@@ -854,6 +909,28 @@ static void console_send_event(CharDrive
     }
 }
 
+static void kbd_send_chars(void *opaque)
+{
+    TextConsole *s = opaque;
+    int len;
+    uint8_t buf[16];
+    
+    len = s->fd_can_read(s->fd_opaque);
+    if (len > s->out_fifo.count)
+        len = s->out_fifo.count;
+    if (len > 0) {
+        if (len > sizeof(buf))
+            len = sizeof(buf);
+        qemu_fifo_read(&s->out_fifo, buf, len);
+        s->fd_read(s->fd_opaque, buf, len);
+    }
+    /* characters are pending: we send them a bit later (XXX:
+       horrible, should change char device API) */
+    if (s->out_fifo.count > 0) {
+        qemu_mod_timer(s->kbd_timer, qemu_get_clock(rt_clock) + 1);
+    }
+}
+
 /* called when an ascii key is pressed */
 void kbd_put_keysym(int keysym)
 {
@@ -879,25 +956,26 @@ void kbd_put_keysym(int keysym)
         console_scroll(10);
         break;
     default:
+        /* convert the QEMU keysym to VT100 key string */
+        q = buf;
+        if (keysym >= 0xe100 && keysym <= 0xe11f) {
+            *q++ = '\033';
+            *q++ = '[';
+            c = keysym - 0xe100;
+            if (c >= 10)
+                *q++ = '0' + (c / 10);
+            *q++ = '0' + (c % 10);
+            *q++ = '~';
+        } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
+            *q++ = '\033';
+            *q++ = '[';
+            *q++ = keysym & 0xff;
+        } else {
+                *q++ = keysym;
+        }
         if (s->fd_read) {
-            /* convert the QEMU keysym to VT100 key string */
-            q = buf;
-            if (keysym >= 0xe100 && keysym <= 0xe11f) {
-                *q++ = '\033';
-                *q++ = '[';
-                c = keysym - 0xe100;
-                if (c >= 10)
-                    *q++ = '0' + (c / 10);
-                *q++ = '0' + (c % 10);
-                *q++ = '~';
-            } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
-                *q++ = '\033';
-                *q++ = '[';
-                *q++ = keysym & 0xff;
-            } else {
-                *q++ = keysym;
-            }
-            s->fd_read(s->fd_opaque, buf, q - buf);
+            qemu_fifo_write(&s->out_fifo, buf, q - buf);
+            kbd_send_chars(s);
         }
         break;
     }
@@ -984,6 +1062,10 @@ CharDriverState *text_console_init(Displ
     chr->chr_add_read_handler = console_chr_add_read_handler;
     chr->chr_send_event = console_send_event;
 
+    s->out_fifo.buf = s->out_fifo_buf;
+    s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
+    s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
+    
     if (!color_inited) {
         color_inited = 1;
         set_color_table(ds);
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/cpu-all.h
--- a/tools/ioemu/cpu-all.h     Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/cpu-all.h     Mon Aug 07 18:25:30 2006 +0100
@@ -878,6 +878,10 @@ extern uint8_t *phys_ram_dirty;
 #define IO_MEM_ROM         (1 << IO_MEM_SHIFT) /* hardcoded offset */
 #define IO_MEM_UNASSIGNED  (2 << IO_MEM_SHIFT)
 #define IO_MEM_NOTDIRTY    (4 << IO_MEM_SHIFT) /* used internally, never use 
directly */
+/* acts like a ROM when read and like a device when written. As an
+   exception, the write memory callback gets the ram offset instead of
+   the physical address */
+#define IO_MEM_ROMD        (1)
 
 typedef void CPUWriteMemoryFunc(void *opaque, target_phys_addr_t addr, 
uint32_t value);
 typedef uint32_t CPUReadMemoryFunc(void *opaque, target_phys_addr_t addr);
@@ -946,13 +950,105 @@ void dump_exec_info(FILE *f,
 void dump_exec_info(FILE *f,
                     int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
 
+/*******************************************/
+/* host CPU ticks (if available) */
+
+#if defined(__powerpc__)
+
+static inline uint32_t get_tbl(void) 
+{
+    uint32_t tbl;
+    asm volatile("mftb %0" : "=r" (tbl));
+    return tbl;
+}
+
+static inline uint32_t get_tbu(void) 
+{
+       uint32_t tbl;
+       asm volatile("mftbu %0" : "=r" (tbl));
+       return tbl;
+}
+
+static inline int64_t cpu_get_real_ticks(void)
+{
+    uint32_t l, h, h1;
+    /* NOTE: we test if wrapping has occurred */
+    do {
+        h = get_tbu();
+        l = get_tbl();
+        h1 = get_tbu();
+    } while (h != h1);
+    return ((int64_t)h << 32) | l;
+}
+
+#elif defined(__i386__)
+
+static inline int64_t cpu_get_real_ticks(void)
+{
+    int64_t val;
+    asm volatile ("rdtsc" : "=A" (val));
+    return val;
+}
+
+#elif defined(__x86_64__)
+
+static inline int64_t cpu_get_real_ticks(void)
+{
+    uint32_t low,high;
+    int64_t val;
+    asm volatile("rdtsc" : "=a" (low), "=d" (high));
+    val = high;
+    val <<= 32;
+    val |= low;
+    return val;
+}
+
+#elif defined(__ia64)
+
+static inline int64_t cpu_get_real_ticks(void)
+{
+       int64_t val;
+       asm volatile ("mov %0 = ar.itc" : "=r"(val) :: "memory");
+       return val;
+}
+
+#elif defined(__s390__)
+
+static inline int64_t cpu_get_real_ticks(void)
+{
+    int64_t val;
+    asm volatile("stck 0(%1)" : "=m" (val) : "a" (&val) : "cc");
+    return val;
+}
+
+#elif defined(__sparc_v9__)
+
+static inline int64_t cpu_get_real_ticks (void)
+{
+#if     defined(_LP64)
+        uint64_t        rval;
+        asm volatile("rd %%tick,%0" : "=r"(rval));
+        return rval;
+#else
+        union {
+                uint64_t i64;
+                struct {
+                        uint32_t high;
+                        uint32_t low;
+                }       i32;
+        } rval;
+        asm volatile("rd %%tick,%1; srlx %1,32,%0"
+                : "=r"(rval.i32.high), "=r"(rval.i32.low));
+        return rval.i64;
+#endif
+}
+#endif
+
 /* profiling */
 #ifdef CONFIG_PROFILER
 static inline int64_t profile_getclock(void)
 {
-    int64_t val;
-    asm volatile ("rdtsc" : "=A" (val));
-    return val;
+    return cpu_get_real_ticks();
 }
 
 extern int64_t kqemu_time, kqemu_time_start;
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/cpu-defs.h
--- a/tools/ioemu/cpu-defs.h    Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/cpu-defs.h    Mon Aug 07 18:25:30 2006 +0100
@@ -47,7 +47,7 @@ typedef uint32_t target_ulong;
 #elif TARGET_LONG_SIZE == 8
 typedef int64_t target_long;
 typedef uint64_t target_ulong;
-#define TARGET_FMT_lx "%016llx"
+#define TARGET_FMT_lx "%016" PRIx64
 #else
 #error TARGET_LONG_SIZE undefined
 #endif
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/cpu-exec.c
--- a/tools/ioemu/cpu-exec.c    Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/cpu-exec.c    Mon Aug 07 18:25:30 2006 +0100
@@ -47,7 +47,7 @@ void cpu_loop_exit(void)
     longjmp(env->jmp_env, 1);
 }
 #endif
-#ifndef TARGET_SPARC
+#if !(defined(TARGET_SPARC) || defined(TARGET_SH4))
 #define reg_T2
 #endif
 
@@ -175,9 +175,13 @@ static inline TranslationBlock *tb_find_
     pc = env->regs[15];
 #elif defined(TARGET_SPARC)
 #ifdef TARGET_SPARC64
-    flags = (env->pstate << 2) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2);
-#else
-    flags = env->psrs | ((env->mmuregs[0] & (MMU_E | MMU_NF)) << 1);
+    // Combined FPU enable bits . PRIV . DMMU enabled . IMMU enabled
+    flags = (((env->pstate & PS_PEF) >> 1) | ((env->fprs & FPRS_FEF) << 2))
+        | (env->pstate & PS_PRIV) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2);
+#else
+    // FPU enable . MMU enabled . MMU no-fault . Supervisor
+    flags = (env->psref << 3) | ((env->mmuregs[0] & (MMU_E | MMU_NF)) << 1)
+        | env->psrs;
 #endif
     cs_base = env->npc;
     pc = env->pc;
@@ -253,7 +257,7 @@ int cpu_exec(CPUState *env1)
     uint32_t *saved_regwptr;
 #endif
 #endif
-#ifdef __sparc__
+#if defined(__sparc__) && !defined(HOST_SOLARIS)
     int saved_i7, tmp_T0;
 #endif
     int ret, interrupt_request;
@@ -323,7 +327,7 @@ int cpu_exec(CPUState *env1)
 #if defined(reg_T2)
     saved_T2 = T2;
 #endif
-#ifdef __sparc__
+#if defined(__sparc__) && !defined(HOST_SOLARIS)
     /* we also save i7 because longjmp may not restore it */
     asm volatile ("mov %%i7, %0" : "=r" (saved_i7));
 #endif
@@ -447,7 +451,7 @@ int cpu_exec(CPUState *env1)
 
             T0 = 0; /* force lookup of first TB */
             for(;;) {
-#ifdef __sparc__
+#if defined(__sparc__) && !defined(HOST_SOLARIS)
                 /* g1 can be modified by some libc? functions */ 
                 tmp_T0 = T0;
 #endif     
@@ -467,7 +471,7 @@ int cpu_exec(CPUState *env1)
                         do_interrupt(intno, 0, 0, 0, 1);
                         /* ensure that no TB jump will be modified as
                            the program flow was changed */
-#ifdef __sparc__
+#if defined(__sparc__) && !defined(HOST_SOLARIS)
                         tmp_T0 = 0;
 #else
                         T0 = 0;
@@ -486,7 +490,7 @@ int cpu_exec(CPUState *env1)
                            env->error_code = 0;
                             do_interrupt(env);
                             env->interrupt_request &= ~CPU_INTERRUPT_HARD;
-#ifdef __sparc__
+#if defined(__sparc__) && !defined(HOST_SOLARIS)
                             tmp_T0 = 0;
 #else
                             T0 = 0;
@@ -497,7 +501,7 @@ int cpu_exec(CPUState *env1)
                             env->error_code = 0;
                             do_interrupt(env);
                             env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
-#ifdef __sparc__
+#if defined(__sparc__) && !defined(HOST_SOLARIS)
                             tmp_T0 = 0;
 #else
                             T0 = 0;
@@ -516,7 +520,7 @@ int cpu_exec(CPUState *env1)
                         env->error_code = 0;
                         do_interrupt(env);
                         env->interrupt_request &= ~CPU_INTERRUPT_HARD;
-#ifdef __sparc__
+#if defined(__sparc__) && !defined(HOST_SOLARIS)
                         tmp_T0 = 0;
 #else
                         T0 = 0;
@@ -534,7 +538,7 @@ int cpu_exec(CPUState *env1)
                            env->interrupt_request &= ~CPU_INTERRUPT_HARD;
                            do_interrupt(env->interrupt_index);
                            env->interrupt_index = 0;
-#ifdef __sparc__
+#if defined(__sparc__) && !defined(HOST_SOLARIS)
                             tmp_T0 = 0;
 #else
                             T0 = 0;
@@ -561,11 +565,13 @@ int cpu_exec(CPUState *env1)
 #elif defined(TARGET_SH4)
                    /* XXXXX */
 #endif
+                   /* Don't use the cached interupt_request value,
+                      do_interrupt may have updated the EXITTB flag. */
                     if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
                         env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
                         /* ensure that no TB jump will be modified as
                            the program flow was changed */
-#ifdef __sparc__
+#if defined(__sparc__) && !defined(HOST_SOLARIS)
                         tmp_T0 = 0;
 #else
                         T0 = 0;
@@ -633,7 +639,7 @@ int cpu_exec(CPUState *env1)
                             lookup_symbol(tb->pc));
                 }
 #endif
-#ifdef __sparc__
+#if defined(__sparc__) && !defined(HOST_SOLARIS)
                 T0 = tmp_T0;
 #endif     
                 /* see if we can patch the calling TB. When the TB
@@ -669,7 +675,9 @@ int cpu_exec(CPUState *env1)
                                      "mov      %%o7,%%i0"
                                      : /* no outputs */
                                      : "r" (gen_func) 
-                                     : "i0", "i1", "i2", "i3", "i4", "i5");
+                                     : "i0", "i1", "i2", "i3", "i4", "i5",
+                                       "l0", "l1", "l2", "l3", "l4", "l5",
+                                       "l6", "l7");
 #elif defined(__arm__)
                 asm volatile ("mov pc, %0\n\t"
                               ".global exec_loop\n\t"
@@ -834,7 +842,7 @@ int cpu_exec(CPUState *env1)
 #else
 #error unsupported target CPU
 #endif
-#ifdef __sparc__
+#if defined(__sparc__) && !defined(HOST_SOLARIS)
     asm volatile ("mov %0, %%i7" : : "r" (saved_i7));
 #endif
     T0 = saved_T0;
@@ -1168,19 +1176,14 @@ static inline int handle_cpu_signal(unsi
            a virtual CPU fault */
         cpu_restore_state(tb, env, pc, puc);
     }
-    if (ret == 1) {
 #if 0
         printf("PF exception: NIP=0x%08x error=0x%x %p\n", 
                env->nip, env->error_code, tb);
 #endif
     /* we restore the process signal mask as the sigreturn should
        do it (XXX: use sigsetjmp) */
-        sigprocmask(SIG_SETMASK, old_set, NULL);
-        //        do_raise_exception_err(env->exception_index, 
env->error_code);
-    } else {
-        /* activate soft MMU for this block */
-        cpu_resume_from_signal(env, puc);
-    }
+    sigprocmask(SIG_SETMASK, old_set, NULL);
+    cpu_loop_exit();
     /* never comes here */
     return 1;
 }
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/disas.c
--- a/tools/ioemu/disas.c       Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/disas.c       Mon Aug 07 18:25:30 2006 +0100
@@ -58,7 +58,7 @@ perror_memory (status, memaddr, info)
     /* Actually, address between memaddr and memaddr + len was
        out of bounds.  */
     (*info->fprintf_func) (info->stream,
-                          "Address 0x%llx is out of bounds.\n", memaddr);
+                          "Address 0x%" PRIx64 " is out of bounds.\n", 
memaddr);
 }
 
 /* This could be in a separate file, to save miniscule amounts of space
@@ -73,7 +73,7 @@ generic_print_address (addr, info)
      bfd_vma addr;
      struct disassemble_info *info;
 {
-    (*info->fprintf_func) (info->stream, "0x%llx", addr);
+    (*info->fprintf_func) (info->stream, "0x%" PRIx64, addr);
 }
 
 /* Just return the given address.  */
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/dyngen-exec.h
--- a/tools/ioemu/dyngen-exec.h Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/dyngen-exec.h Mon Aug 07 18:25:30 2006 +0100
@@ -35,11 +35,14 @@ typedef unsigned char uint8_t;
 typedef unsigned char uint8_t;
 typedef unsigned short uint16_t;
 typedef unsigned int uint32_t;
+// Linux/Sparc64 defines uint64_t
+#if !(defined (__sparc_v9__) && defined(__linux__))
 /* XXX may be done for all 64 bits targets ? */
 #if defined (__x86_64__) || defined(__ia64)
 typedef unsigned long uint64_t;
 #else
 typedef unsigned long long uint64_t;
+#endif
 #endif
 
 /* if Solaris/__sun__, don't typedef int8_t, as it will be typedef'd
@@ -50,10 +53,13 @@ typedef signed char int8_t;
 #endif
 typedef signed short int16_t;
 typedef signed int int32_t;
+// Linux/Sparc64 defines int64_t
+#if !(defined (__sparc_v9__) && defined(__linux__))
 #if defined (__x86_64__) || defined(__ia64)
 typedef signed long int64_t;
 #else
 typedef signed long long int64_t;
+#endif
 #endif
 
 #define INT8_MIN               (-128)
@@ -121,6 +127,19 @@ extern int printf(const char *, ...);
 #define AREG3 "s2"
 #endif
 #ifdef __sparc__
+#ifdef HOST_SOLARIS
+#define AREG0 "g2"
+#define AREG1 "g3"
+#define AREG2 "g4"
+#define AREG3 "g5"
+#define AREG4 "g6"
+#else
+#ifdef __sparc_v9__
+#define AREG0 "g1"
+#define AREG1 "g4"
+#define AREG2 "g5"
+#define AREG3 "g7"
+#else
 #define AREG0 "g6"
 #define AREG1 "g1"
 #define AREG2 "g2"
@@ -133,6 +152,8 @@ extern int printf(const char *, ...);
 #define AREG9 "l5"
 #define AREG10 "l6"
 #define AREG11 "l7"
+#endif
+#endif
 #define USE_FP_CONVERT
 #endif
 #ifdef __s390__
@@ -241,10 +262,8 @@ extern int __op_jmp0, __op_jmp1, __op_jm
                                          ASM_NAME(__op_gen_label) #n)
 #endif
 #ifdef __sparc__
-#define EXIT_TB() asm volatile ("jmpl %i0 + 8, %g0\n" \
-                                "nop")
-#define        GOTO_LABEL_PARAM(n) asm volatile ( \
-               "set " ASM_NAME(__op_gen_label) #n ", %g1; jmp %g1; nop")
+#define EXIT_TB() asm volatile ("jmpl %i0 + 8, %g0; nop")
+#define GOTO_LABEL_PARAM(n) asm volatile ("ba " ASM_NAME(__op_gen_label) #n 
";nop")
 #endif
 #ifdef __arm__
 #define EXIT_TB() asm volatile ("b exec_loop")
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/dyngen.c
--- a/tools/ioemu/dyngen.c      Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/dyngen.c      Mon Aug 07 18:25:30 2006 +0100
@@ -1196,7 +1196,7 @@ void get_reloc_expr(char *name, int name
     } else {
 #ifdef HOST_SPARC
         if (sym_name[0] == '.')
-            snprintf(name, sizeof(name),
+            snprintf(name, name_size,
                      "(long)(&__dot_%s)",
                      sym_name + 1);
         else
@@ -1440,6 +1440,15 @@ void gen_code(const char *name, host_ulo
     }
 #elif defined(HOST_SPARC)
     {
+#define INSN_SAVE       0x9de3a000
+#define INSN_RET        0x81c7e008
+#define INSN_RETL       0x81c3e008
+#define INSN_RESTORE    0x81e80000
+#define INSN_RETURN     0x81cfe008
+#define INSN_NOP        0x01000000
+#define INSN_ADD_SP     0x9c03a000 // add %sp, nn, %sp
+#define INSN_SUB_SP     0x9c23a000 // sub %sp, nn, %sp
+
         uint32_t start_insn, end_insn1, end_insn2;
         uint8_t *p;
         p = (void *)(p_end - 8);
@@ -1448,13 +1457,21 @@ void gen_code(const char *name, host_ulo
         start_insn = get32((uint32_t *)(p_start + 0x0));
         end_insn1 = get32((uint32_t *)(p + 0x0));
         end_insn2 = get32((uint32_t *)(p + 0x4));
-        if ((start_insn & ~0x1fff) == 0x9de3a000) {
+        if (((start_insn & ~0x1fff) == INSN_SAVE) ||
+            (start_insn & ~0x1fff) == INSN_ADD_SP) {
             p_start += 0x4;
             start_offset += 0x4;
-            if ((int)(start_insn | ~0x1fff) < -128)
-                error("Found bogus save at the start of %s", name);
-            if (end_insn1 != 0x81c7e008 || end_insn2 != 0x81e80000)
+            if (end_insn1 == INSN_RET && end_insn2 == INSN_RESTORE)
+                /* SPARC v7: ret; restore; */ ;
+            else if (end_insn1 == INSN_RETURN && end_insn2 == INSN_NOP)
+                /* SPARC v9: return; nop; */ ;
+            else if (end_insn1 == INSN_RETL && (end_insn2 & ~0x1fff) == 
INSN_SUB_SP)
+                /* SPARC v7: retl; sub %sp, nn, %sp; */ ;
+            else
+
                 error("ret; restore; not found at end of %s", name);
+        } else if (end_insn1 == INSN_RETL && end_insn2 == INSN_NOP) {
+            ;
         } else {
             error("No save at the beginning of %s", name);
         }
@@ -1462,7 +1479,7 @@ void gen_code(const char *name, host_ulo
         /* Skip a preceeding nop, if present.  */
         if (p > p_start) {
             skip_insn = get32((uint32_t *)(p - 0x4));
-            if (skip_insn == 0x01000000)
+            if (skip_insn == INSN_NOP)
                 p -= 4;
         }
 #endif
@@ -1470,21 +1487,41 @@ void gen_code(const char *name, host_ulo
     }
 #elif defined(HOST_SPARC64)
     {
+#define INSN_SAVE       0x9de3a000
+#define INSN_RET        0x81c7e008
+#define INSN_RETL       0x81c3e008
+#define INSN_RESTORE    0x81e80000
+#define INSN_RETURN     0x81cfe008
+#define INSN_NOP        0x01000000
+#define INSN_ADD_SP     0x9c03a000 // add %sp, nn, %sp
+#define INSN_SUB_SP     0x9c23a000 // sub %sp, nn, %sp
+
         uint32_t start_insn, end_insn1, end_insn2, skip_insn;
         uint8_t *p;
         p = (void *)(p_end - 8);
+#if 0
+        /* XXX: check why it occurs */
         if (p <= p_start)
             error("empty code for %s", name);
+#endif
         start_insn = get32((uint32_t *)(p_start + 0x0));
         end_insn1 = get32((uint32_t *)(p + 0x0));
         end_insn2 = get32((uint32_t *)(p + 0x4));
-        if ((start_insn & ~0x1fff) == 0x9de3a000) {
+        if (((start_insn & ~0x1fff) == INSN_SAVE) ||
+            (start_insn & ~0x1fff) == INSN_ADD_SP) {
             p_start += 0x4;
             start_offset += 0x4;
-            if ((int)(start_insn | ~0x1fff) < -256)
-                error("Found bogus save at the start of %s", name);
-            if (end_insn1 != 0x81c7e008 || end_insn2 != 0x81e80000)
+            if (end_insn1 == INSN_RET && end_insn2 == INSN_RESTORE)
+                /* SPARC v7: ret; restore; */ ;
+            else if (end_insn1 == INSN_RETURN && end_insn2 == INSN_NOP)
+                /* SPARC v9: return; nop; */ ;
+            else if (end_insn1 == INSN_RETL && (end_insn2 & ~0x1fff) == 
INSN_SUB_SP)
+                /* SPARC v7: retl; sub %sp, nn, %sp; */ ;
+            else
+
                 error("ret; restore; not found at end of %s", name);
+        } else if (end_insn1 == INSN_RETL && end_insn2 == INSN_NOP) {
+            ;
         } else {
             error("No save at the beginning of %s", name);
         }
@@ -2151,6 +2188,18 @@ void gen_code(const char *name, host_ulo
                                    reloc_offset, reloc_offset, name, addend,
                                    reloc_offset);
                            break;
+                        case R_SPARC_WDISP22:
+                            fprintf(outfile,
+                                    "    *(uint32_t *)(gen_code_ptr + %d) = "
+                                    "((*(uint32_t *)(gen_code_ptr + %d)) "
+                                    " & ~0x3fffff) "
+                                    " | ((((%s + %d) - (long)(gen_code_ptr + 
%d))>>2) "
+                                    "    & 0x3fffff);\n",
+                                    rel->r_offset - start_offset,
+                                    rel->r_offset - start_offset,
+                                    name, addend,
+                                    rel->r_offset - start_offset);
+                            break;
                         default:
                             error("unsupported sparc relocation (%d)", type);
                         }
@@ -2168,7 +2217,7 @@ void gen_code(const char *name, host_ulo
                        rel->r_offset < start_offset + copy_size) {
                         sym_name = strtab + 
symtab[ELF64_R_SYM(rel->r_info)].st_name;
                         get_reloc_expr(name, sizeof(name), sym_name);
-                        type = ELF64_R_TYPE(rel->r_info);
+                        type = ELF32_R_TYPE(rel->r_info);
                         addend = rel->r_addend;
                         reloc_offset = rel->r_offset - start_offset;
                         switch(type) {
@@ -2192,6 +2241,15 @@ void gen_code(const char *name, host_ulo
                                    " | ((%s + %d) & 0x3ff);\n",
                                     reloc_offset, reloc_offset, name, addend);
                            break;
+                        case R_SPARC_OLO10:
+                            addend += ELF64_R_TYPE_DATA (rel->r_info);
+                            fprintf(outfile,
+                                   "    *(uint32_t *)(gen_code_ptr + %d) = "
+                                   "((*(uint32_t *)(gen_code_ptr + %d)) "
+                                   " & ~0x3ff) "
+                                   " | ((%s + %d) & 0x3ff);\n",
+                                    reloc_offset, reloc_offset, name, addend);
+                           break;
                        case R_SPARC_WDISP30:
                            fprintf(outfile,
                                    "    *(uint32_t *)(gen_code_ptr + %d) = "
@@ -2202,8 +2260,18 @@ void gen_code(const char *name, host_ulo
                                    reloc_offset, reloc_offset, name, addend,
                                    reloc_offset);
                            break;
+                        case R_SPARC_WDISP22:
+                            fprintf(outfile,
+                                    "    *(uint32_t *)(gen_code_ptr + %d) = "
+                                    "((*(uint32_t *)(gen_code_ptr + %d)) "
+                                    " & ~0x3fffff) "
+                                    " | ((((%s + %d) - (long)(gen_code_ptr + 
%d))>>2) "
+                                    "    & 0x3fffff);\n",
+                                    reloc_offset, reloc_offset, name, addend,
+                                   reloc_offset);
+                            break;
                         default:
-                           error("unsupported sparc64 relocation (%d)", type);
+                           error("unsupported sparc64 relocation (%d) for 
symbol %s", type, name);
                         }
                     }
                 }
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/dyngen.h
--- a/tools/ioemu/dyngen.h      Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/dyngen.h      Mon Aug 07 18:25:30 2006 +0100
@@ -19,7 +19,13 @@
  */
 
 int __op_param1, __op_param2, __op_param3;
-int __op_gen_label1, __op_gen_label2, __op_gen_label3;
+#ifdef __sparc__
+  void __op_gen_label1(){}
+  void __op_gen_label2(){}
+  void __op_gen_label3(){}
+#else
+  int __op_gen_label1, __op_gen_label2, __op_gen_label3;
+#endif
 int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3;
 
 #ifdef __i386__
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/elf.h
--- a/tools/ioemu/elf.h Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/elf.h Mon Aug 07 18:25:30 2006 +0100
@@ -227,6 +227,7 @@ typedef struct {
 
 #define ELF64_R_SYM(i)                 ((i) >> 32)
 #define ELF64_R_TYPE(i)                        ((i) & 0xffffffff)
+#define ELF64_R_TYPE_DATA(i)            (((ELF64_R_TYPE(i) >> 8) ^ 0x00800000) 
- 0x00800000)
 
 #define R_386_NONE     0
 #define R_386_32       1
@@ -326,6 +327,7 @@ typedef struct {
 #define R_SPARC_10             30
 #define R_SPARC_11             31
 #define R_SPARC_64             32
+#define R_SPARC_OLO10           33
 #define R_SPARC_WDISP16                40
 #define R_SPARC_WDISP19                41
 #define R_SPARC_7              43
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/exec-all.h
--- a/tools/ioemu/exec-all.h    Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/exec-all.h    Mon Aug 07 18:25:30 2006 +0100
@@ -571,7 +571,7 @@ static inline target_ulong get_phys_addr
         ldub_code(addr);
     }
     pd = env->tlb_table[is_user][index].addr_code & ~TARGET_PAGE_MASK;
-    if (pd > IO_MEM_ROM) {
+    if (pd > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
         cpu_abort(env, "Trying to execute code outside RAM or ROM at 
0x%08lx\n", addr);
     }
     return addr + env->tlb_table[is_user][index].addend - (unsigned 
long)phys_ram_base;
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/exec.c
--- a/tools/ioemu/exec.c        Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/exec.c        Mon Aug 07 18:25:30 2006 +0100
@@ -1488,7 +1488,7 @@ int tlb_set_page_exec(CPUState *env, tar
     if (is_softmmu) 
 #endif
     {
-        if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
+        if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
             /* IO memory case */
             address = vaddr | pd;
             addend = paddr;
@@ -1513,9 +1513,11 @@ int tlb_set_page_exec(CPUState *env, tar
             te->addr_code = -1;
         }
         if (prot & PAGE_WRITE) {
-            if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM) {
-                /* ROM: access is ignored (same as unassigned) */
-                te->addr_write = vaddr | IO_MEM_ROM;
+            if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM || 
+                (pd & IO_MEM_ROMD)) {
+                /* write access calls the I/O callback */
+                te->addr_write = vaddr | 
+                    (pd & ~(TARGET_PAGE_MASK | IO_MEM_ROMD));
             } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM && 
                        !cpu_physical_memory_is_dirty(pd)) {
                 te->addr_write = vaddr | IO_MEM_NOTDIRTY;
@@ -1779,14 +1781,23 @@ void cpu_register_physical_memory(target
 {
     target_phys_addr_t addr, end_addr;
     PhysPageDesc *p;
+    CPUState *env;
 
     size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
     end_addr = start_addr + size;
     for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
         p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
         p->phys_offset = phys_offset;
-        if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM)
+        if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
+            (phys_offset & IO_MEM_ROMD))
             phys_offset += TARGET_PAGE_SIZE;
+    }
+    
+    /* since each CPU stores ram addresses in its TLB cache, we must
+       reset the modified entries */
+    /* XXX: slow ! */
+    for(env = first_cpu; env != NULL; env = env->next_cpu) {
+        tlb_flush(env, 1);
     }
 }
 
@@ -2048,7 +2059,8 @@ void cpu_physical_memory_rw(target_phys_
                 }
             }
         } else {
-            if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
+            if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && 
+                !(pd & IO_MEM_ROMD)) {
                 /* I/O case */
                 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
                 if (l >= 4 && ((addr & 3) == 0)) {
@@ -2103,7 +2115,8 @@ void cpu_physical_memory_write_rom(targe
         }
         
         if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM &&
-            (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM) {
+            (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM &&
+            !(pd & IO_MEM_ROMD)) {
             /* do nothing */
         } else {
             unsigned long addr1;
@@ -2135,7 +2148,8 @@ uint32_t ldl_phys(target_phys_addr_t add
         pd = p->phys_offset;
     }
         
-    if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
+    if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && 
+        !(pd & IO_MEM_ROMD)) {
         /* I/O case */
         io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
         val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
@@ -2164,7 +2178,8 @@ uint64_t ldq_phys(target_phys_addr_t add
         pd = p->phys_offset;
     }
         
-    if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
+    if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
+        !(pd & IO_MEM_ROMD)) {
         /* I/O case */
         io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
 #ifdef TARGET_WORDS_BIGENDIAN
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/fpu/softfloat-native.c
--- a/tools/ioemu/fpu/softfloat-native.c        Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/fpu/softfloat-native.c        Mon Aug 07 18:25:30 2006 +0100
@@ -6,7 +6,7 @@ void set_float_rounding_mode(int val STA
 void set_float_rounding_mode(int val STATUS_PARAM)
 {
     STATUS(float_rounding_mode) = val;
-#if defined(_BSD) && !defined(__APPLE__)
+#if defined(_BSD) && !defined(__APPLE__) || (defined(HOST_SOLARIS) && 
HOST_SOLARIS < 10)
     fpsetround(val);
 #elif defined(__arm__)
     /* nothing to do */
@@ -22,9 +22,14 @@ void set_floatx80_rounding_precision(int
 }
 #endif
 
-#if defined(_BSD)
-#define lrint(d)               ((long)rint(d))
-#define llrint(d)              ((long long)rint(d))
+#if defined(_BSD) || (defined(HOST_SOLARIS) && HOST_SOLARIS < 10)
+#define lrint(d)               ((int32_t)rint(d))
+#define llrint(d)              ((int64_t)rint(d))
+#define lrintf(f)              ((int32_t)rint(f))
+#define llrintf(f)             ((int64_t)rint(f))
+#define sqrtf(f)               ((float)sqrt(f))
+#define remainderf(fa, fb)     ((float)remainder(fa, fb))
+#define rintf(f)               ((float)rint(f))
 #endif
 
 #if defined(__powerpc__)
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/gdbstub.c
--- a/tools/ioemu/gdbstub.c     Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/gdbstub.c     Mon Aug 07 18:25:30 2006 +0100
@@ -17,6 +17,7 @@
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
+#include "config.h"
 #ifdef CONFIG_USER_ONLY
 #include <stdlib.h>
 #include <stdio.h>
@@ -24,16 +25,25 @@
 #include <string.h>
 #include <errno.h>
 #include <unistd.h>
+#include <fcntl.h>
 
 #include "qemu.h"
 #else
 #include "vl.h"
 #endif
 
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
+#include "qemu_socket.h"
+#ifdef _WIN32
+/* XXX: these constants may be independent of the host ones even for Unix */
+#ifndef SIGTRAP
+#define SIGTRAP 5
+#endif
+#ifndef SIGINT
+#define SIGINT 2
+#endif
+#else
 #include <signal.h>
+#endif
 
 //#define DEBUG_GDB
 
@@ -69,7 +79,7 @@ static int get_char(GDBState *s)
     int ret;
 
     for(;;) {
-        ret = read(s->fd, &ch, 1);
+        ret = recv(s->fd, &ch, 1, 0);
         if (ret < 0) {
             if (errno != EINTR && errno != EAGAIN)
                 return -1;
@@ -87,7 +97,7 @@ static void put_buffer(GDBState *s, cons
     int ret;
 
     while (len > 0) {
-        ret = write(s->fd, buf, len);
+        ret = send(s->fd, buf, len, 0);
         if (ret < 0) {
             if (errno != EINTR && errno != EAGAIN)
                 return;
@@ -305,11 +315,11 @@ static int cpu_gdb_read_registers(CPUSta
     for(i = 0; i < 24; i++) {
         registers[i + 8] = tswapl(env->regwptr[i]);
     }
+#ifndef TARGET_SPARC64
     /* fill in fprs */
     for (i = 0; i < 32; i++) {
         registers[i + 32] = tswapl(*((uint32_t *)&env->fpr[i]));
     }
-#ifndef TARGET_SPARC64
     /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
     registers[64] = tswapl(env->y);
     {
@@ -327,16 +337,21 @@ static int cpu_gdb_read_registers(CPUSta
     registers[72] = 0;
     return 73 * sizeof(target_ulong);
 #else
-    for (i = 0; i < 32; i += 2) {
-        registers[i/2 + 64] = tswapl(*((uint64_t *)&env->fpr[i]));
-    }
-    registers[81] = tswapl(env->pc);
-    registers[82] = tswapl(env->npc);
-    registers[83] = tswapl(env->tstate[env->tl]);
-    registers[84] = tswapl(env->fsr);
-    registers[85] = tswapl(env->fprs);
-    registers[86] = tswapl(env->y);
-    return 87 * sizeof(target_ulong);
+    /* fill in fprs */
+    for (i = 0; i < 64; i += 2) {
+       uint64_t tmp;
+
+        tmp = (uint64_t)tswap32(*((uint32_t *)&env->fpr[i])) << 32;
+        tmp |= tswap32(*((uint32_t *)&env->fpr[i + 1]));
+        registers[i/2 + 32] = tmp;
+    }
+    registers[64] = tswapl(env->pc);
+    registers[65] = tswapl(env->npc);
+    registers[66] = tswapl(env->tstate[env->tl]);
+    registers[67] = tswapl(env->fsr);
+    registers[68] = tswapl(env->fprs);
+    registers[69] = tswapl(env->y);
+    return 70 * sizeof(target_ulong);
 #endif
 }
 
@@ -353,11 +368,11 @@ static void cpu_gdb_write_registers(CPUS
     for(i = 0; i < 24; i++) {
         env->regwptr[i] = tswapl(registers[i + 8]);
     }
+#ifndef TARGET_SPARC64
     /* fill in fprs */
     for (i = 0; i < 32; i++) {
         *((uint32_t *)&env->fpr[i]) = tswapl(registers[i + 32]);
     }
-#ifndef TARGET_SPARC64
     /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
     env->y = tswapl(registers[64]);
     PUT_PSR(env, tswapl(registers[65]));
@@ -367,18 +382,16 @@ static void cpu_gdb_write_registers(CPUS
     env->npc = tswapl(registers[69]);
     env->fsr = tswapl(registers[70]);
 #else
-    for (i = 0; i < 32; i += 2) {
-       uint64_t tmp;
-       tmp = tswapl(registers[i/2 + 64]) << 32;
-       tmp |= tswapl(registers[i/2 + 64 + 1]);
-        *((uint64_t *)&env->fpr[i]) = tmp;
-    }
-    env->pc = tswapl(registers[81]);
-    env->npc = tswapl(registers[82]);
-    env->tstate[env->tl] = tswapl(registers[83]);
-    env->fsr = tswapl(registers[84]);
-    env->fprs = tswapl(registers[85]);
-    env->y = tswapl(registers[86]);
+    for (i = 0; i < 64; i += 2) {
+       *((uint32_t *)&env->fpr[i]) = tswap32(registers[i/2 + 32] >> 32);
+       *((uint32_t *)&env->fpr[i + 1]) = tswap32(registers[i/2 + 32] & 
0xffffffff);
+    }
+    env->pc = tswapl(registers[64]);
+    env->npc = tswapl(registers[65]);
+    env->tstate[env->tl] = tswapl(registers[66]);
+    env->fsr = tswapl(registers[67]);
+    env->fprs = tswapl(registers[68]);
+    env->y = tswapl(registers[69]);
 #endif
 }
 #elif defined (TARGET_ARM)
@@ -494,7 +507,12 @@ static int cpu_gdb_read_registers(CPUSta
   int i;
 
 #define SAVE(x) *ptr++=tswapl(x)
-  for (i = 0; i < 16; i++) SAVE(env->gregs[i]);
+  if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) {
+      for (i = 0; i < 8; i++) SAVE(env->gregs[i + 16]);
+  } else {
+      for (i = 0; i < 8; i++) SAVE(env->gregs[i]);
+  }
+  for (i = 8; i < 16; i++) SAVE(env->gregs[i]);
   SAVE (env->pc);
   SAVE (env->pr);
   SAVE (env->gbr);
@@ -517,7 +535,12 @@ static void cpu_gdb_write_registers(CPUS
   int i;
 
 #define LOAD(x) (x)=*ptr++;
-  for (i = 0; i < 16; i++) LOAD(env->gregs[i]);
+  if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) {
+      for (i = 0; i < 8; i++) LOAD(env->gregs[i + 16]);
+  } else {
+      for (i = 0; i < 8; i++) LOAD(env->gregs[i]);
+  }
+  for (i = 8; i < 16; i++) LOAD(env->gregs[i]);
   LOAD (env->pc);
   LOAD (env->pr);
   LOAD (env->gbr);
@@ -545,7 +568,7 @@ static int gdb_handle_packet(GDBState *s
     char buf[4096];
     uint8_t mem_buf[2000];
     uint32_t *registers;
-    uint32_t addr, len;
+    target_ulong addr, len;
     
 #ifdef DEBUG_GDB
     printf("command='%s'\n", line_buf);
@@ -560,7 +583,7 @@ static int gdb_handle_packet(GDBState *s
         break;
     case 'c':
         if (*p != '\0') {
-            addr = strtoul(p, (char **)&p, 16);
+            addr = strtoull(p, (char **)&p, 16);
 #if defined(TARGET_I386)
             env->eip = addr;
 #elif defined (TARGET_PPC)
@@ -616,10 +639,10 @@ static int gdb_handle_packet(GDBState *s
         put_packet(s, "OK");
         break;
     case 'm':
-        addr = strtoul(p, (char **)&p, 16);
+        addr = strtoull(p, (char **)&p, 16);
         if (*p == ',')
             p++;
-        len = strtoul(p, NULL, 16);
+        len = strtoull(p, NULL, 16);
         if (cpu_memory_rw_debug(env, addr, mem_buf, len, 0) != 0) {
             put_packet (s, "E14");
         } else {
@@ -628,10 +651,10 @@ static int gdb_handle_packet(GDBState *s
         }
         break;
     case 'M':
-        addr = strtoul(p, (char **)&p, 16);
+        addr = strtoull(p, (char **)&p, 16);
         if (*p == ',')
             p++;
-        len = strtoul(p, (char **)&p, 16);
+        len = strtoull(p, (char **)&p, 16);
         if (*p == ':')
             p++;
         hextomem(mem_buf, p, len);
@@ -644,10 +667,10 @@ static int gdb_handle_packet(GDBState *s
         type = strtoul(p, (char **)&p, 16);
         if (*p == ',')
             p++;
-        addr = strtoul(p, (char **)&p, 16);
+        addr = strtoull(p, (char **)&p, 16);
         if (*p == ',')
             p++;
-        len = strtoul(p, (char **)&p, 16);
+        len = strtoull(p, (char **)&p, 16);
         if (type == 0 || type == 1) {
             if (cpu_breakpoint_insert(env, addr) < 0)
                 goto breakpoint_error;
@@ -661,10 +684,10 @@ static int gdb_handle_packet(GDBState *s
         type = strtoul(p, (char **)&p, 16);
         if (*p == ',')
             p++;
-        addr = strtoul(p, (char **)&p, 16);
+        addr = strtoull(p, (char **)&p, 16);
         if (*p == ',')
             p++;
-        len = strtoul(p, (char **)&p, 16);
+        len = strtoull(p, (char **)&p, 16);
         if (type == 0 || type == 1) {
             cpu_breakpoint_remove(env, addr);
             put_packet(s, "OK");
@@ -672,6 +695,18 @@ static int gdb_handle_packet(GDBState *s
             goto breakpoint_error;
         }
         break;
+#ifdef CONFIG_USER_ONLY
+    case 'q':
+        if (strncmp(p, "Offsets", 7) == 0) {
+            TaskState *ts = env->opaque;
+
+            sprintf(buf, "Text=%x;Data=%x;Bss=%x", ts->info->code_offset,
+                ts->info->data_offset, ts->info->data_offset);
+            put_packet(s, buf);
+            break;
+        }
+        /* Fall through.  */
+#endif
     default:
         //        unknown_command:
         /* put empty packet */
@@ -829,7 +864,7 @@ static void gdb_read(void *opaque)
     int i, size;
     uint8_t buf[4096];
 
-    size = read(s->fd, buf, sizeof(buf));
+    size = recv(s->fd, buf, sizeof(buf), 0);
     if (size < 0)
         return;
     if (size == 0) {
@@ -866,7 +901,7 @@ static void gdb_accept(void *opaque)
 
     /* set short latency */
     val = 1;
-    setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
+    setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
     
 #ifdef CONFIG_USER_ONLY
     s = &gdbserver_state;
@@ -881,9 +916,11 @@ static void gdb_accept(void *opaque)
     s->env = first_cpu; /* XXX: allow to change CPU */
     s->fd = fd;
 
+#ifdef CONFIG_USER_ONLY
     fcntl(fd, F_SETFL, O_NONBLOCK);
-
-#ifndef CONFIG_USER_ONLY
+#else
+    socket_set_nonblock(fd);
+
     /* stop the VM */
     vm_stop(EXCP_INTERRUPT);
 
@@ -907,7 +944,7 @@ static int gdbserver_open(int port)
 
     /* allow fast reuse */
     val = 1;
-    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
+    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
 
     sockaddr.sin_family = AF_INET;
     sockaddr.sin_port = htons(port);
@@ -923,7 +960,7 @@ static int gdbserver_open(int port)
         return -1;
     }
 #ifndef CONFIG_USER_ONLY
-    fcntl(fd, F_SETFL, O_NONBLOCK);
+    socket_set_nonblock(fd);
 #endif
     return fd;
 }
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/adlib.c
--- a/tools/ioemu/hw/adlib.c    Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/hw/adlib.c    Mon Aug 07 18:25:30 2006 +0100
@@ -301,6 +301,7 @@ int Adlib_init (AudioState *audio)
     as.freq = conf.freq;
     as.nchannels = SHIFT;
     as.fmt = AUD_FMT_S16;
+    as.endianness = AUDIO_HOST_ENDIANNESS;
 
     AUD_register_card (audio, "adlib", &s->card);
 
@@ -310,8 +311,7 @@ int Adlib_init (AudioState *audio)
         "adlib",
         s,
         adlib_callback,
-        &as,
-        0                       /* XXX: little endian? */
+        &as
         );
     if (!s->voice) {
         Adlib_fini (s);
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/apic.c
--- a/tools/ioemu/hw/apic.c     Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/hw/apic.c     Mon Aug 07 18:25:30 2006 +0100
@@ -239,7 +239,7 @@ void cpu_set_apic_base(CPUState *env, ui
 {
     APICState *s = env->apic_state;
 #ifdef DEBUG_APIC
-    printf("cpu_set_apic_base: %016llx\n", val);
+    printf("cpu_set_apic_base: %016" PRIx64 "\n", val);
 #endif
     s->apicbase = (val & 0xfffff000) | 
         (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
@@ -255,7 +255,7 @@ uint64_t cpu_get_apic_base(CPUState *env
 {
     APICState *s = env->apic_state;
 #ifdef DEBUG_APIC
-    printf("cpu_get_apic_base: %016llx\n", (uint64_t)s->apicbase);
+    printf("cpu_get_apic_base: %016" PRIx64 "\n", (uint64_t)s->apicbase);
 #endif
     return s->apicbase;
 }
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/cuda.c
--- a/tools/ioemu/hw/cuda.c     Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/hw/cuda.c     Mon Aug 07 18:25:30 2006 +0100
@@ -209,7 +209,7 @@ static int64_t get_next_irq_time(CUDATim
     }
 #if 0
 #ifdef DEBUG_CUDA
-    printf("latch=%d counter=%lld delta_next=%lld\n", 
+    printf("latch=%d counter=%" PRId64 " delta_next=%" PRId64 "\n", 
            s->latch, d, next_time - d);
 #endif
 #endif
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/es1370.c
--- a/tools/ioemu/hw/es1370.c   Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/hw/es1370.c   Mon Aug 07 18:25:30 2006 +0100
@@ -423,6 +423,7 @@ static void es1370_update_voices (ES1370
                 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 =
@@ -432,8 +433,7 @@ static void es1370_update_voices (ES1370
                             "es1370.adc",
                             s,
                             es1370_adc_callback,
-                            &as,
-                            0   /* little endian */
+                            &as
                             );
                 }
                 else {
@@ -444,8 +444,7 @@ static void es1370_update_voices (ES1370
                             i ? "es1370.dac2" : "es1370.dac1",
                             s,
                             i ? es1370_dac2_callback : es1370_dac1_callback,
-                            &as,
-                            0   /* litle endian */
+                            &as
                             );
                 }
             }
@@ -479,8 +478,9 @@ IO_WRITE_PROTO (es1370_writeb)
 IO_WRITE_PROTO (es1370_writeb)
 {
     ES1370State *s = opaque;
+    uint32_t shift, mask;
+
     addr = es1370_fixup (s, addr);
-    uint32_t shift, mask;
 
     switch (addr) {
     case ES1370_REG_CONTROL:
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/esp.c
--- a/tools/ioemu/hw/esp.c      Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/hw/esp.c      Mon Aug 07 18:25:30 2006 +0100
@@ -38,16 +38,13 @@ do { printf("ESP: set_irq(%d): %d\n", (i
 #define ESPDMA_REGS 4
 #define ESPDMA_MAXADDR (ESPDMA_REGS * 4 - 1)
 #define ESP_MAXREG 0x3f
-#define TI_BUFSZ 1024*1024 // XXX
+#define TI_BUFSZ 32
 #define DMA_VER 0xa0000000
 #define DMA_INTR 1
 #define DMA_INTREN 0x10
+#define DMA_WRITE_MEM 0x100
 #define DMA_LOADED 0x04000000
 typedef struct ESPState ESPState;
-
-typedef int ESPDMAFunc(ESPState *s, 
-                       target_phys_addr_t phys_addr, 
-                       int transfer_size1);
 
 struct ESPState {
     BlockDriverState **bd;
@@ -57,12 +54,14 @@ struct ESPState {
     uint32_t espdmaregs[ESPDMA_REGS];
     uint32_t ti_size;
     uint32_t ti_rptr, ti_wptr;
-    int ti_dir;
     uint8_t ti_buf[TI_BUFSZ];
+    int sense;
     int dma;
-    ESPDMAFunc *dma_cb;
-    int64_t offset, len;
-    int target;
+    SCSIDevice *scsi_dev[MAX_DISKS];
+    SCSIDevice *current_dev;
+    uint8_t cmdbuf[TI_BUFSZ];
+    int cmdlen;
+    int do_cmd;
 };
 
 #define STAT_DO 0x00
@@ -83,394 +82,200 @@ struct ESPState {
 #define SEQ_0 0x0
 #define SEQ_CD 0x4
 
-/* XXX: stolen from ide.c, move to common ATAPI/SCSI library */
-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;
-}
-
-static inline void cpu_to_ube16(uint8_t *buf, int val)
-{
-    buf[0] = val >> 8;
-    buf[1] = val;
-}
-
-static inline void cpu_to_ube32(uint8_t *buf, unsigned int val)
-{
-    buf[0] = val >> 24;
-    buf[1] = val >> 16;
-    buf[2] = val >> 8;
-    buf[3] = val;
-}
-
-/* same toc as bochs. Return -1 if error or the toc length */
-/* XXX: check this */
-static 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_ube32(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_ube32(q, nb_sectors);
-        q += 4;
-    }
-    len = q - buf;
-    cpu_to_ube16(buf, len - 2);
-    return len;
-}
-
-/* mostly same info as PearPc */
-static 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_ube32(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_ube16(buf, len - 2);
-    return len;
-}
-
-static int esp_write_dma_cb(ESPState *s, 
-                            target_phys_addr_t phys_addr, 
-                            int transfer_size1)
-{
-    DPRINTF("Write callback (offset %lld len %lld size %d trans_size %d)\n",
-            s->offset, s->len, s->ti_size, transfer_size1);
-    bdrv_write(s->bd[s->target], s->offset, s->ti_buf, s->len);
-    s->offset = 0;
-    s->len = 0;
-    s->target = 0;
-    return 0;
-}
-
-static void handle_satn(ESPState *s)
-{
-    uint8_t buf[32];
+static int get_cmd(ESPState *s, uint8_t *buf)
+{
     uint32_t dmaptr, dmalen;
-    unsigned int i;
-    int64_t nb_sectors;
     int target;
 
     dmalen = s->wregs[0] | (s->wregs[1] << 8);
     target = s->wregs[4] & 7;
-    DPRINTF("Select with ATN len %d target %d\n", dmalen, target);
+    DPRINTF("get_cmd: len %d target %d\n", dmalen, target);
     if (s->dma) {
        dmaptr = iommu_translate(s->espdmaregs[1]);
-       DPRINTF("DMA Direction: %c, addr 0x%8.8x\n", s->espdmaregs[0] & 0x100? 
'w': 'r', dmaptr);
+       DPRINTF("DMA Direction: %c, addr 0x%8.8x\n",
+                s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', dmaptr);
        cpu_physical_memory_read(dmaptr, buf, dmalen);
     } else {
        buf[0] = 0;
        memcpy(&buf[1], s->ti_buf, dmalen);
        dmalen++;
     }
-    for (i = 0; i < dmalen; i++) {
-       DPRINTF("Command %2.2x\n", buf[i]);
-    }
-    s->ti_dir = 0;
+
     s->ti_size = 0;
     s->ti_rptr = 0;
     s->ti_wptr = 0;
 
-    if (target >= 4 || !s->bd[target]) { // No such drive
+    if (target >= 4 || !s->scsi_dev[target]) {
+        // No such drive
        s->rregs[4] = STAT_IN;
        s->rregs[5] = INTR_DC;
        s->rregs[6] = SEQ_0;
        s->espdmaregs[0] |= DMA_INTR;
        pic_set_irq(s->irq, 1);
-       return;
-    }
-    switch (buf[1]) {
-    case 0x0:
-       DPRINTF("Test Unit Ready (len %d)\n", buf[5]);
-       break;
-    case 0x12:
-       DPRINTF("Inquiry (len %d)\n", buf[5]);
-       memset(s->ti_buf, 0, 36);
-       if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) {
-           s->ti_buf[0] = 5;
-           memcpy(&s->ti_buf[16], "QEMU CDROM     ", 16);
-       } else {
-           s->ti_buf[0] = 0;
-           memcpy(&s->ti_buf[16], "QEMU HARDDISK  ", 16);
-       }
-       memcpy(&s->ti_buf[8], "QEMU   ", 8);
-       s->ti_buf[2] = 1;
-       s->ti_buf[3] = 2;
-       s->ti_buf[4] = 32;
-       s->ti_dir = 1;
-       s->ti_size = 36;
-       break;
-    case 0x1a:
-       DPRINTF("Mode Sense(6) (page %d, len %d)\n", buf[3], buf[5]);
-       break;
-    case 0x25:
-       DPRINTF("Read Capacity (len %d)\n", buf[5]);
-       memset(s->ti_buf, 0, 8);
-       bdrv_get_geometry(s->bd[target], &nb_sectors);
-       s->ti_buf[0] = (nb_sectors >> 24) & 0xff;
-       s->ti_buf[1] = (nb_sectors >> 16) & 0xff;
-       s->ti_buf[2] = (nb_sectors >> 8) & 0xff;
-       s->ti_buf[3] = nb_sectors & 0xff;
-       s->ti_buf[4] = 0;
-       s->ti_buf[5] = 0;
-       if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM)
-           s->ti_buf[6] = 8; // sector size 2048
-       else
-           s->ti_buf[6] = 2; // sector size 512
-       s->ti_buf[7] = 0;
-       s->ti_dir = 1;
-       s->ti_size = 8;
-       break;
-    case 0x28:
-       {
-           int64_t offset, len;
-
-           if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) {
-               offset = ((buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | 
buf[6]) * 4;
-               len = ((buf[8] << 8) | buf[9]) * 4;
-               s->ti_size = len * 2048;
-           } else {
-               offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | 
buf[6];
-               len = (buf[8] << 8) | buf[9];
-               s->ti_size = len * 512;
-           }
-           DPRINTF("Read (10) (offset %lld len %lld)\n", offset, len);
-            if (s->ti_size > TI_BUFSZ) {
-                DPRINTF("size too large %d\n", s->ti_size);
-            }
-           bdrv_read(s->bd[target], offset, s->ti_buf, len);
-           // XXX error handling
-           s->ti_dir = 1;
-           break;
-       }
-    case 0x2a:
-       {
-           int64_t offset, len;
-
-           if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) {
-               offset = ((buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | 
buf[6]) * 4;
-               len = ((buf[8] << 8) | buf[9]) * 4;
-               s->ti_size = len * 2048;
-           } else {
-               offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | 
buf[6];
-               len = (buf[8] << 8) | buf[9];
-               s->ti_size = len * 512;
-           }
-           DPRINTF("Write (10) (offset %lld len %lld)\n", offset, len);
-            if (s->ti_size > TI_BUFSZ) {
-                DPRINTF("size too large %d\n", s->ti_size);
-            }
-            s->dma_cb = esp_write_dma_cb;
-            s->offset = offset;
-            s->len = len;
-            s->target = target;
-           // XXX error handling
-           s->ti_dir = 0;
-           break;
-       }
-    case 0x43:
-        {
-            int start_track, format, msf, len;
-
-            msf = buf[2] & 2;
-            format = buf[3] & 0xf;
-            start_track = buf[7];
-            bdrv_get_geometry(s->bd[target], &nb_sectors);
-            DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, 
format, msf >> 1);
-            switch(format) {
-            case 0:
-                len = cdrom_read_toc(nb_sectors, buf, msf, start_track);
-                if (len < 0)
-                    goto error_cmd;
-                s->ti_size = len;
-                break;
-            case 1:
-                /* multi session : only a single session defined */
-                memset(buf, 0, 12);
-                buf[1] = 0x0a;
-                buf[2] = 0x01;
-                buf[3] = 0x01;
-                s->ti_size = 12;
-                break;
-            case 2:
-                len = cdrom_read_toc_raw(nb_sectors, buf, msf, start_track);
-                if (len < 0)
-                    goto error_cmd;
-                s->ti_size = len;
-                break;
-            default:
-            error_cmd:
-                DPRINTF("Read TOC error\n");
-                // XXX error handling
-                break;
-            }
-           s->ti_dir = 1;
-            break;
-        }
-    default:
-       DPRINTF("Unknown SCSI command (%2.2x)\n", buf[1]);
-       break;
-    }
-    s->rregs[4] = STAT_IN | STAT_TC | STAT_DI;
+       return 0;
+    }
+    s->current_dev = s->scsi_dev[target];
+    return dmalen;
+}
+
+static void do_cmd(ESPState *s, uint8_t *buf)
+{
+    int32_t datalen;
+    int lun;
+
+    DPRINTF("do_cmd: busid 0x%x\n", buf[0]);
+    lun = buf[0] & 7;
+    datalen = scsi_send_command(s->current_dev, 0, &buf[1], lun);
+    if (datalen == 0) {
+        s->ti_size = 0;
+    } else {
+        s->rregs[4] = STAT_IN | STAT_TC;
+        if (datalen > 0) {
+            s->rregs[4] |= STAT_DI;
+            s->ti_size = datalen;
+        } else {
+            s->rregs[4] |= STAT_DO;
+            s->ti_size = -datalen;
+        }
+    }
     s->rregs[5] = INTR_BS | INTR_FC;
     s->rregs[6] = SEQ_CD;
     s->espdmaregs[0] |= DMA_INTR;
     pic_set_irq(s->irq, 1);
 }
 
-static void dma_write(ESPState *s, const uint8_t *buf, uint32_t len)
-{
-    uint32_t dmaptr, dmalen;
-
-    dmalen = s->wregs[0] | (s->wregs[1] << 8);
-    DPRINTF("Transfer status len %d\n", dmalen);
+static void handle_satn(ESPState *s)
+{
+    uint8_t buf[32];
+    int len;
+
+    len = get_cmd(s, buf);
+    if (len)
+        do_cmd(s, buf);
+}
+
+static void handle_satn_stop(ESPState *s)
+{
+    s->cmdlen = get_cmd(s, s->cmdbuf);
+    if (s->cmdlen) {
+        DPRINTF("Set ATN & Stop: cmdlen %d\n", s->cmdlen);
+        s->do_cmd = 1;
+        s->espdmaregs[1] += s->cmdlen;
+        s->rregs[4] = STAT_IN | STAT_TC | STAT_CD;
+        s->rregs[5] = INTR_BS | INTR_FC;
+        s->rregs[6] = SEQ_CD;
+        s->espdmaregs[0] |= DMA_INTR;
+        pic_set_irq(s->irq, 1);
+    }
+}
+
+static void write_response(ESPState *s)
+{
+    uint32_t dmaptr;
+
+    DPRINTF("Transfer status (sense=%d)\n", s->sense);
+    s->ti_buf[0] = s->sense;
+    s->ti_buf[1] = 0;
     if (s->dma) {
        dmaptr = iommu_translate(s->espdmaregs[1]);
-       DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r');
-       cpu_physical_memory_write(dmaptr, buf, len);
+       DPRINTF("DMA Direction: %c\n",
+                s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r');
+       cpu_physical_memory_write(dmaptr, s->ti_buf, 2);
        s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
        s->rregs[5] = INTR_BS | INTR_FC;
        s->rregs[6] = SEQ_CD;
     } else {
-       memcpy(s->ti_buf, buf, len);
-       s->ti_size = dmalen;
+       s->ti_size = 2;
        s->ti_rptr = 0;
        s->ti_wptr = 0;
-       s->rregs[7] = dmalen;
+       s->rregs[7] = 2;
     }
     s->espdmaregs[0] |= DMA_INTR;
     pic_set_irq(s->irq, 1);
 
 }
 
-static const uint8_t okbuf[] = {0, 0};
+static void esp_command_complete(void *opaque, uint32_t tag, int sense)
+{
+    ESPState *s = (ESPState *)opaque;
+
+    DPRINTF("SCSI Command complete\n");
+    if (s->ti_size != 0)
+        DPRINTF("SCSI command completed unexpectedly\n");
+    s->ti_size = 0;
+    if (sense)
+        DPRINTF("Command failed\n");
+    s->sense = sense;
+    s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
+}
 
 static void handle_ti(ESPState *s)
 {
-    uint32_t dmaptr, dmalen;
+    uint32_t dmaptr, dmalen, minlen, len, from, to;
     unsigned int i;
+    int to_device;
+    uint8_t buf[TARGET_PAGE_SIZE];
 
     dmalen = s->wregs[0] | (s->wregs[1] << 8);
-    DPRINTF("Transfer Information len %d\n", dmalen);
+    if (dmalen==0) {
+      dmalen=0x10000;
+    }
+
+    if (s->do_cmd)
+        minlen = (dmalen < 32) ? dmalen : 32;
+    else
+        minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size;
+    DPRINTF("Transfer Information len %d\n", minlen);
     if (s->dma) {
        dmaptr = iommu_translate(s->espdmaregs[1]);
-       DPRINTF("DMA Direction: %c, addr 0x%8.8x\n", s->espdmaregs[0] & 0x100? 
'w': 'r', dmaptr);
-       for (i = 0; i < s->ti_size; i++) {
+        /* Check if the transfer writes to to reads from the device.  */
+        to_device = (s->espdmaregs[0] & DMA_WRITE_MEM) == 0;
+       DPRINTF("DMA Direction: %c, addr 0x%8.8x %08x\n",
+                to_device ? 'r': 'w', dmaptr, s->ti_size);
+       from = s->espdmaregs[1];
+       to = from + minlen;
+       for (i = 0; i < minlen; i += len, from += len) {
            dmaptr = iommu_translate(s->espdmaregs[1] + i);
-           if (s->ti_dir)
-               cpu_physical_memory_write(dmaptr, &s->ti_buf[i], 1);
-           else
-               cpu_physical_memory_read(dmaptr, &s->ti_buf[i], 1);
-       }
-        if (s->dma_cb) {
-            s->dma_cb(s, s->espdmaregs[1], dmalen);
-            s->dma_cb = NULL;
-        }
-       s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
-       s->rregs[5] = INTR_BS;
+           if ((from & TARGET_PAGE_MASK) != (to & TARGET_PAGE_MASK)) {
+               len = TARGET_PAGE_SIZE - (from & ~TARGET_PAGE_MASK);
+            } else {
+              len = to - from;
+            }
+            DPRINTF("DMA address p %08x v %08x len %08x, from %08x, to 
%08x\n", dmaptr, s->espdmaregs[1] + i, len, from, to);
+            s->ti_size -= len;
+            if (s->do_cmd) {
+                DPRINTF("command len %d + %d\n", s->cmdlen, len);
+                cpu_physical_memory_read(dmaptr, &s->cmdbuf[s->cmdlen], len);
+                s->ti_size = 0;
+                s->cmdlen = 0;
+                s->do_cmd = 0;
+                do_cmd(s, s->cmdbuf);
+                return;
+            } else {
+                if (to_device) {
+                    cpu_physical_memory_read(dmaptr, buf, len);
+                    scsi_write_data(s->current_dev, buf, len);
+                } else {
+                    scsi_read_data(s->current_dev, buf, len);
+                    cpu_physical_memory_write(dmaptr, buf, len);
+                }
+            }
+        }
+        if (s->ti_size) {
+           s->rregs[4] = STAT_IN | STAT_TC | (to_device ? STAT_DO : STAT_DI);
+        }
+        s->rregs[5] = INTR_BS;
        s->rregs[6] = 0;
+       s->rregs[7] = 0;
        s->espdmaregs[0] |= DMA_INTR;
-    } else {
-       s->ti_size = dmalen;
-       s->ti_rptr = 0;
-       s->ti_wptr = 0;
-       s->rregs[7] = dmalen;
-    }  
+    } else if (s->do_cmd) {
+        DPRINTF("command len %d\n", s->cmdlen);
+        s->ti_size = 0;
+        s->cmdlen = 0;
+        s->do_cmd = 0;
+        do_cmd(s, s->cmdbuf);
+        return;
+    }
     pic_set_irq(s->irq, 1);
 }
 
@@ -484,9 +289,8 @@ static void esp_reset(void *opaque)
     s->ti_size = 0;
     s->ti_rptr = 0;
     s->ti_wptr = 0;
-    s->ti_dir = 0;
     s->dma = 0;
-    s->dma_cb = NULL;
+    s->do_cmd = 0;
 }
 
 static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)
@@ -501,7 +305,12 @@ static uint32_t esp_mem_readb(void *opaq
        // FIFO
        if (s->ti_size > 0) {
            s->ti_size--;
-           s->rregs[saddr] = s->ti_buf[s->ti_rptr++];
+            if ((s->rregs[4] & 6) == 0) {
+                /* Data in/out.  */
+                scsi_read_data(s->current_dev, &s->rregs[2], 0);
+            } else {
+                s->rregs[2] = s->ti_buf[s->ti_rptr++];
+            }
            pic_set_irq(s->irq, 1);
        }
        if (s->ti_size == 0) {
@@ -536,8 +345,17 @@ static void esp_mem_writeb(void *opaque,
         break;
     case 2:
        // FIFO
-       s->ti_size++;
-       s->ti_buf[s->ti_wptr++] = val & 0xff;
+        if (s->do_cmd) {
+            s->cmdbuf[s->cmdlen++] = val & 0xff;
+        } else if ((s->rregs[4] & 6) == 0) {
+            uint8_t buf;
+            buf = val & 0xff;
+            s->ti_size--;
+            scsi_write_data(s->current_dev, &buf, 0);
+        } else {
+            s->ti_size++;
+            s->ti_buf[s->ti_wptr++] = val & 0xff;
+        }
        break;
     case 3:
         s->rregs[saddr] = val;
@@ -574,11 +392,11 @@ static void esp_mem_writeb(void *opaque,
            break;
        case 0x11:
            DPRINTF("Initiator Command Complete Sequence (%2.2x)\n", val);
-           dma_write(s, okbuf, 2);
+           write_response(s);
            break;
        case 0x12:
            DPRINTF("Message Accepted (%2.2x)\n", val);
-           dma_write(s, okbuf, 2);
+           write_response(s);
            s->rregs[5] = INTR_DC;
            s->rregs[6] = 0;
            break;
@@ -586,11 +404,12 @@ static void esp_mem_writeb(void *opaque,
            DPRINTF("Set ATN (%2.2x)\n", val);
            break;
        case 0x42:
+           DPRINTF("Set ATN (%2.2x)\n", val);
            handle_satn(s);
            break;
        case 0x43:
            DPRINTF("Set ATN & stop (%2.2x)\n", val);
-           handle_satn(s);
+           handle_satn_stop(s);
            break;
        default:
            DPRINTF("Unhandled ESP command (%2.2x)\n", val);
@@ -660,7 +479,7 @@ static void espdma_mem_writel(void *opaq
         val |= DMA_VER;
        break;
     case 1:
-        s->espdmaregs[0] = DMA_LOADED;
+        s->espdmaregs[0] |= DMA_LOADED;
         break;
     default:
        break;
@@ -693,7 +512,6 @@ static void esp_save(QEMUFile *f, void *
     qemu_put_be32s(f, &s->ti_size);
     qemu_put_be32s(f, &s->ti_rptr);
     qemu_put_be32s(f, &s->ti_wptr);
-    qemu_put_be32s(f, &s->ti_dir);
     qemu_put_buffer(f, s->ti_buf, TI_BUFSZ);
     qemu_put_be32s(f, &s->dma);
 }
@@ -714,7 +532,6 @@ static int esp_load(QEMUFile *f, void *o
     qemu_get_be32s(f, &s->ti_size);
     qemu_get_be32s(f, &s->ti_rptr);
     qemu_get_be32s(f, &s->ti_wptr);
-    qemu_get_be32s(f, &s->ti_dir);
     qemu_get_buffer(f, s->ti_buf, TI_BUFSZ);
     qemu_get_be32s(f, &s->dma);
 
@@ -725,6 +542,7 @@ void esp_init(BlockDriverState **bd, int
 {
     ESPState *s;
     int esp_io_memory, espdma_io_memory;
+    int i;
 
     s = qemu_mallocz(sizeof(ESPState));
     if (!s)
@@ -743,5 +561,11 @@ void esp_init(BlockDriverState **bd, int
 
     register_savevm("esp", espaddr, 1, esp_save, esp_load, s);
     qemu_register_reset(esp_reset, s);
-}
-
+    for (i = 0; i < MAX_DISKS; i++) {
+        if (bs_table[i]) {
+            s->scsi_dev[i] =
+                scsi_disk_init(bs_table[i], esp_command_complete, s);
+        }
+    }
+}
+
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/i8259.c
--- a/tools/ioemu/hw/i8259.c    Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/hw/i8259.c    Mon Aug 07 18:25:30 2006 +0100
@@ -531,7 +531,7 @@ void irq_info(void)
     for (i = 0; i < 16; i++) {
         count = irq_count[i];
         if (count > 0)
-            term_printf("%2d: %lld\n", i, count);
+            term_printf("%2d: %" PRId64 "\n", i, count);
     }
 #endif
 }
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/ide.c
--- a/tools/ioemu/hw/ide.c      Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/hw/ide.c      Mon Aug 07 18:25:30 2006 +0100
@@ -1133,127 +1133,6 @@ static void ide_atapi_cmd_read(IDEState 
     }
 }
 
-/* same toc as bochs. Return -1 if error or the toc length */
-/* XXX: check this */
-static int cdrom_read_toc(IDEState *s, uint8_t *buf, int msf, int start_track)
-{
-    uint8_t *q;
-    int nb_sectors, 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_ube32(q, 0);
-            q += 4;
-        }
-    }
-    /* lead out track */
-    *q++ = 0; /* reserved */
-    *q++ = 0x16; /* ADR, control */
-    *q++ = 0xaa; /* track number */
-    *q++ = 0; /* reserved */
-    nb_sectors = s->nb_sectors >> 2;
-    if (msf) {
-        *q++ = 0; /* reserved */
-        lba_to_msf(q, nb_sectors);
-        q += 3;
-    } else {
-        cpu_to_ube32(q, nb_sectors);
-        q += 4;
-    }
-    len = q - buf;
-    cpu_to_ube16(buf, len - 2);
-    return len;
-}
-
-/* mostly same info as PearPc */
-static int cdrom_read_toc_raw(IDEState *s, uint8_t *buf, int msf, 
-                              int session_num)
-{
-    uint8_t *q;
-    int nb_sectors, 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 */
-    nb_sectors = s->nb_sectors >> 2;
-    if (msf) {
-        *q++ = 0; /* reserved */
-        lba_to_msf(q, nb_sectors);
-        q += 3;
-    } else {
-        cpu_to_ube32(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_ube16(buf, len - 2);
-    return len;
-}
-
 static void ide_atapi_cmd(IDEState *s)
 {
     const uint8_t *packet;
@@ -1501,7 +1380,7 @@ static void ide_atapi_cmd(IDEState *s)
             start_track = packet[6];
             switch(format) {
             case 0:
-                len = cdrom_read_toc(s, buf, msf, start_track);
+                len = cdrom_read_toc(s->nb_sectors >> 2, buf, msf, 
start_track);
                 if (len < 0)
                     goto error_cmd;
                 ide_atapi_cmd_reply(s, len, max_len);
@@ -1515,7 +1394,7 @@ static void ide_atapi_cmd(IDEState *s)
                 ide_atapi_cmd_reply(s, 12, max_len);
                 break;
             case 2:
-                len = cdrom_read_toc_raw(s, buf, msf, start_track);
+                len = cdrom_read_toc_raw(s->nb_sectors >> 2, buf, msf, 
start_track);
                 if (len < 0)
                     goto error_cmd;
                 ide_atapi_cmd_reply(s, len, max_len);
@@ -1829,6 +1708,11 @@ static void ide_ioport_write(void *opaqu
             break;
         case WIN_FLUSH_CACHE:
         case WIN_FLUSH_CACHE_EXT:
+            if (s->bs)
+                bdrv_flush(s->bs);
+           s->status = READY_STAT;
+            ide_set_irq(s);
+            break;
        case WIN_STANDBYNOW1:
         case WIN_IDLEIMMEDIATE:
            s->status = READY_STAT;
@@ -2563,7 +2447,7 @@ void pci_cmd646_ide_init(PCIBus *bus, Bl
 
 /* hd_table must contain 4 block drivers */
 /* NOTE: for the PIIX3, the IRQs and IOports are hardcoded */
-void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table)
+void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn)
 {
     PCIIDEState *d;
     uint8_t *pci_conf;
@@ -2571,7 +2455,7 @@ void pci_piix3_ide_init(PCIBus *bus, Blo
     /* register a function 1 of PIIX3 */
     d = (PCIIDEState *)pci_register_device(bus, "PIIX3 IDE", 
                                            sizeof(PCIIDEState),
-                                           ((PCIDevice *)piix3_state)->devfn + 
1, 
+                                           devfn,
                                            NULL, NULL);
     d->type = IDE_TYPE_PIIX3;
 
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/m48t59.c
--- a/tools/ioemu/hw/m48t59.c   Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/hw/m48t59.c   Mon Aug 07 18:25:30 2006 +0100
@@ -332,7 +332,10 @@ void m48t59_write (m48t59_t *NVRAM, uint
        tmp = fromBCD(val);
        if (tmp >= 0 && tmp <= 99) {
            get_time(NVRAM, &tm);
-           tm.tm_year = fromBCD(val);
+            if (NVRAM->type == 8)
+                tm.tm_year = fromBCD(val) + 68; // Base year is 1968
+            else
+                tm.tm_year = fromBCD(val);
            set_time(NVRAM, &tm);
        }
         break;
@@ -421,7 +424,10 @@ uint32_t m48t59_read (m48t59_t *NVRAM, u
     case 0x1FFF:
         /* year */
         get_time(NVRAM, &tm);
-        retval = toBCD(tm.tm_year);
+        if (NVRAM->type == 8) 
+            retval = toBCD(tm.tm_year - 68); // Base year is 1968
+        else
+            retval = toBCD(tm.tm_year);
         break;
     default:
         /* Check lock registers state */
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/mips_r4k.c
--- a/tools/ioemu/hw/mips_r4k.c Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/hw/mips_r4k.c Mon Aug 07 18:25:30 2006 +0100
@@ -60,7 +60,7 @@ static void cpu_mips_update_count (CPUSt
        next++;
 #if 0
     if (logfile) {
-        fprintf(logfile, "%s: 0x%08llx %08x %08x => 0x%08llx\n",
+        fprintf(logfile, "%s: 0x%08" PRIx64 " %08x %08x => 0x%08" PRIx64 "\n",
                 __func__, now, count, compare, next - now);
     }
 #endif
@@ -214,14 +214,10 @@ void mips_r4k_init (int ram_size, int vg
        run. */
     bios_offset = ram_size + vga_ram_size;
     snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
-    printf("%s: load BIOS '%s' size %d\n", __func__, buf, BIOS_SIZE);
     ret = load_image(buf, phys_ram_base + bios_offset);
     if (ret == BIOS_SIZE) {
        cpu_register_physical_memory((uint32_t)(0x1fc00000),
                                     BIOS_SIZE, bios_offset | IO_MEM_ROM);
-       env->PC = 0xBFC00000;
-       if (!kernel_filename)
-           return;
     } else {
        /* not fatal */
         fprintf(stderr, "qemu: Warning, could not load MIPS bios '%s'\n",
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/ne2000.c
--- a/tools/ioemu/hw/ne2000.c   Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/hw/ne2000.c   Mon Aug 07 18:25:30 2006 +0100
@@ -206,7 +206,7 @@ static int ne2000_buffer_full(NE2000Stat
 
     index = s->curpag << 8;
     boundary = s->boundary << 8;
-    if (index < boundary)
+    if (index <= boundary)
         avail = boundary - index;
     else
         avail = (s->stop - s->start) - (index - boundary);
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/pc.c
--- a/tools/ioemu/hw/pc.c       Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/hw/pc.c       Mon Aug 07 18:25:30 2006 +0100
@@ -44,7 +44,6 @@ static PITState *pit;
 #ifndef CONFIG_DM
 static IOAPICState *ioapic;
 #endif /* !CONFIG_DM */
-static USBPort *usb_root_ports[2];
 
 static void ioport80_write(void *opaque, uint32_t addr, uint32_t data)
 {
@@ -63,10 +62,19 @@ static void ioportF0_write(void *opaque,
 }
 
 /* TSC handling */
-
 uint64_t cpu_get_tsc(CPUX86State *env)
 {
-    return qemu_get_clock(vm_clock);
+    /* Note: when using kqemu, it is more logical to return the host TSC
+       because kqemu does not trap the RDTSC instruction for
+       performance reasons */
+#if USE_KQEMU
+    if (env->kqemu_enabled) {
+        return cpu_get_real_ticks();
+    } else 
+#endif
+    {
+        return cpu_get_ticks();
+    }
 }
 
 #ifndef CONFIG_DM
@@ -201,6 +209,8 @@ static void cmos_init(uint64_t ram_size,
     case 'a':
     case 'b':
         rtc_set_memory(s, 0x3d, 0x01); /* floppy boot */
+        if (!fd_bootchk)
+            rtc_set_memory(s, 0x38, 0x01); /* disable signature check */
         break;
     default:
     case 'c':
@@ -272,10 +282,6 @@ static void cmos_init(uint64_t ram_size,
         }
     }
     rtc_set_memory(s, 0x39, val);
-
-    /* Disable check of 0x55AA signature on the last two bytes of
-       first sector of disk. XXX: make it the default ? */
-    //    rtc_set_memory(s, 0x38, 1);
 }
 
 void ioport_set_a20(int enable)
@@ -567,7 +573,7 @@ static int parallel_irq[MAX_PARALLEL_POR
 static int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 };
 
 /* PIIX4 acpi pci configuration space, func 3 */
-extern void pci_piix4_acpi_init(PCIBus *bus);
+extern void pci_piix4_acpi_init(PCIBus *bus, int devfn);
 
 #ifdef HAS_AUDIO
 static void audio_init (PCIBus *pci_bus)
@@ -630,6 +636,7 @@ static void pc_init1(uint64_t ram_size, 
     int bios_size, isa_bios_size;
 #endif /* !NOBIOS */
     PCIBus *pci_bus;
+    int piix3_devfn = -1;
     CPUState *env;
     NICInfo *nd;
 
@@ -774,7 +781,7 @@ static void pc_init1(uint64_t ram_size, 
 
     if (pci_enabled) {
         pci_bus = i440fx_init();
-        piix3_init(pci_bus);
+        piix3_devfn = piix3_init(pci_bus);
     } else {
         pci_bus = NULL;
     }
@@ -852,7 +859,7 @@ static void pc_init1(uint64_t ram_size, 
     }
 
     if (pci_enabled) {
-        pci_piix3_ide_init(pci_bus, bs_table);
+        pci_piix3_ide_init(pci_bus, bs_table, piix3_devfn + 1);
     } else {
         for(i = 0; i < 2; i++) {
             isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i],
@@ -872,17 +879,39 @@ static void pc_init1(uint64_t ram_size, 
 
     /* using PIIX4 acpi model */
     if (pci_enabled && acpi_enabled)
-        pci_piix4_acpi_init(pci_bus);
+        pci_piix4_acpi_init(pci_bus, piix3_devfn + 3);
 
     if (pci_enabled && usb_enabled) {
-        usb_uhci_init(pci_bus, usb_root_ports);
-        usb_attach(usb_root_ports[0], vm_usb_hub);
-    }
-
+        usb_uhci_init(pci_bus, piix3_devfn + 2);
+    }
+
+    if (pci_enabled && acpi_enabled && 0) {
+        piix4_pm_init(pci_bus, piix3_devfn + 3);
+    }
+
+#if 0
+    /* ??? Need to figure out some way for the user to
+       specify SCSI devices.  */
+    if (pci_enabled) {
+        void *scsi;
+        BlockDriverState *bdrv;
+
+        scsi = lsi_scsi_init(pci_bus, -1);
+        bdrv = bdrv_new("scsidisk");
+        bdrv_open(bdrv, "scsi_disk.img", 0);
+        lsi_scsi_attach(scsi, bdrv, -1);
+        bdrv = bdrv_new("scsicd");
+        bdrv_open(bdrv, "scsi_cd.iso", 0);
+        bdrv_set_type_hint(bdrv, BDRV_TYPE_CDROM);
+        lsi_scsi_attach(scsi, bdrv, -1);
+    }
+#endif
     /* must be done after all PCI devices are instanciated */
     /* XXX: should be done in the Bochs BIOS */
     if (pci_enabled) {
         pci_bios_init();
+        if (acpi_enabled)
+            acpi_bios_init();
     }
 }
 
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/pci.c
--- a/tools/ioemu/hw/pci.c      Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/hw/pci.c      Mon Aug 07 18:25:30 2006 +0100
@@ -25,25 +25,10 @@
 
 //#define DEBUG_PCI
 
-#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_CLASS_DEVICE        0x0a    /* Device class */
-#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 */
-
-/* just used for simpler irq handling. */
-#define PCI_DEVICES_MAX 64
-#define PCI_IRQ_WORDS   ((PCI_DEVICES_MAX + 31) / 32)
-
 struct PCIBus {
     int bus_num;
     int devfn_min;
-    void (*set_irq)(PCIDevice *pci_dev, int irq_num, int level);
+    pci_set_irq_fn set_irq;
     uint32_t config_reg; /* XXX: suppress */
     /* low level pic */
     SetIRQFunc *low_set_irq;
@@ -53,15 +38,22 @@ struct PCIBus {
 
 target_phys_addr_t pci_mem_base;
 static int pci_irq_index;
-static uint32_t pci_irq_levels[4][PCI_IRQ_WORDS];
 static PCIBus *first_bus;
 
-static PCIBus *pci_register_bus(void)
+PCIBus *pci_register_bus(pci_set_irq_fn set_irq, void *pic, int devfn_min)
 {
     PCIBus *bus;
     bus = qemu_mallocz(sizeof(PCIBus));
+    bus->set_irq = set_irq;
+    bus->irq_opaque = pic;
+    bus->devfn_min = devfn_min;
     first_bus = bus;
     return bus;
+}
+
+int pci_bus_num(PCIBus *s)
+{
+    return s->bus_num;
 }
 
 void generic_pci_save(QEMUFile* f, void *opaque)
@@ -141,16 +133,9 @@ void pci_register_io_region(PCIDevice *p
     *(uint32_t *)(pci_dev->config + addr) = cpu_to_le32(type);
 }
 
-static void pci_addr_writel(void* opaque, uint32_t addr, uint32_t val)
-{
-    PCIBus *s = opaque;
-    s->config_reg = val;
-}
-
-static uint32_t pci_addr_readl(void* opaque, uint32_t addr)
-{
-    PCIBus *s = opaque;
-    return s->config_reg;
+target_phys_addr_t pci_to_cpu_addr(target_phys_addr_t addr)
+{
+    return addr + pci_mem_base;
 }
 
 static void pci_update_mappings(PCIDevice *d)
@@ -218,7 +203,7 @@ static void pci_update_mappings(PCIDevic
                             isa_unassign_ioport(r->addr, r->size);
                         }
                     } else {
-                        cpu_register_physical_memory(r->addr + pci_mem_base, 
+                        cpu_register_physical_memory(pci_to_cpu_addr(r->addr),
                                                      r->size, 
                                                      IO_MEM_UNASSIGNED);
                     }
@@ -346,8 +331,7 @@ void pci_default_write_config(PCIDevice 
     }
 }
 
-static void pci_data_write(void *opaque, uint32_t addr, 
-                           uint32_t val, int len)
+void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len)
 {
     PCIBus *s = opaque;
     PCIDevice *pci_dev;
@@ -355,18 +339,15 @@ static void pci_data_write(void *opaque,
     
 #if defined(DEBUG_PCI) && 0
     printf("pci_data_write: addr=%08x val=%08x len=%d\n",
-           s->config_reg, val, len);
+           addr, val, len);
 #endif
-    if (!(s->config_reg & (1 << 31))) {
-        return;
-    }
-    bus_num = (s->config_reg >> 16) & 0xff;
+    bus_num = (addr >> 16) & 0xff;
     if (bus_num != 0)
         return;
-    pci_dev = s->devices[(s->config_reg >> 8) & 0xff];
+    pci_dev = s->devices[(addr >> 8) & 0xff];
     if (!pci_dev)
         return;
-    config_addr = (s->config_reg & 0xfc) | (addr & 3);
+    config_addr = addr & 0xff;
 #if defined(DEBUG_PCI)
     printf("pci_config_write: %s: addr=%02x val=%08x len=%d\n",
            pci_dev->name, config_addr, val, len);
@@ -374,20 +355,17 @@ static void pci_data_write(void *opaque,
     pci_dev->config_write(pci_dev, config_addr, val, len);
 }
 
-static uint32_t pci_data_read(void *opaque, uint32_t addr, 
-                              int len)
+uint32_t pci_data_read(void *opaque, uint32_t addr, int len)
 {
     PCIBus *s = opaque;
     PCIDevice *pci_dev;
     int config_addr, bus_num;
     uint32_t val;
 
-    if (!(s->config_reg & (1 << 31)))
-        goto fail;
-    bus_num = (s->config_reg >> 16) & 0xff;
+    bus_num = (addr >> 16) & 0xff;
     if (bus_num != 0)
         goto fail;
-    pci_dev = s->devices[(s->config_reg >> 8) & 0xff];
+    pci_dev = s->devices[(addr >> 8) & 0xff];
     if (!pci_dev) {
     fail:
         switch(len) {
@@ -404,7 +382,7 @@ static uint32_t pci_data_read(void *opaq
         }
         goto the_end;
     }
-    config_addr = (s->config_reg & 0xfc) | (addr & 3);
+    config_addr = addr & 0xff;
     val = pci_dev->config_read(pci_dev, config_addr, len);
 #if defined(DEBUG_PCI)
     printf("pci_config_read: %s: addr=%02x val=%08x len=%d\n",
@@ -413,1133 +391,11 @@ static uint32_t pci_data_read(void *opaq
  the_end:
 #if defined(DEBUG_PCI) && 0
     printf("pci_data_read: addr=%08x val=%08x len=%d\n",
-           s->config_reg, val, len);
+           addr, val, len);
 #endif
     return val;
 }
 
-static void pci_data_writeb(void* opaque, uint32_t addr, uint32_t val)
-{
-    pci_data_write(opaque, addr, val, 1);
-}
-
-static void pci_data_writew(void* opaque, uint32_t addr, uint32_t val)
-{
-    pci_data_write(opaque, addr, val, 2);
-}
-
-static void pci_data_writel(void* opaque, uint32_t addr, uint32_t val)
-{
-    pci_data_write(opaque, addr, val, 4);
-}
-
-static uint32_t pci_data_readb(void* opaque, uint32_t addr)
-{
-    return pci_data_read(opaque, addr, 1);
-}
-
-static uint32_t pci_data_readw(void* opaque, uint32_t addr)
-{
-    return pci_data_read(opaque, addr, 2);
-}
-
-static uint32_t pci_data_readl(void* opaque, uint32_t addr)
-{
-    return pci_data_read(opaque, addr, 4);
-}
-
-/* i440FX PCI bridge */
-
-static void piix3_set_irq(PCIDevice *pci_dev, int irq_num, int level);
-
-PCIBus *i440fx_init(void)
-{
-    PCIBus *s;
-    PCIDevice *d;
-
-    s = pci_register_bus();
-    s->set_irq = piix3_set_irq;
-
-    register_ioport_write(0xcf8, 4, 4, pci_addr_writel, s);
-    register_ioport_read(0xcf8, 4, 4, pci_addr_readl, s);
-
-    register_ioport_write(0xcfc, 4, 1, pci_data_writeb, s);
-    register_ioport_write(0xcfc, 4, 2, pci_data_writew, s);
-    register_ioport_write(0xcfc, 4, 4, pci_data_writel, s);
-    register_ioport_read(0xcfc, 4, 1, pci_data_readb, s);
-    register_ioport_read(0xcfc, 4, 2, pci_data_readw, s);
-    register_ioport_read(0xcfc, 4, 4, pci_data_readl, s);
-
-    d = pci_register_device(s, "i440FX", sizeof(PCIDevice), 0, 
-                            NULL, NULL);
-
-    d->config[0x00] = 0x86; // vendor_id
-    d->config[0x01] = 0x80;
-    d->config[0x02] = 0x37; // device_id
-    d->config[0x03] = 0x12;
-    d->config[0x08] = 0x02; // revision
-    d->config[0x0a] = 0x00; // class_sub = host2pci
-    d->config[0x0b] = 0x06; // class_base = PCI_bridge
-    d->config[0x0e] = 0x00; // header_type
-    return s;
-}
-
-/* PIIX3 PCI to ISA bridge */
-
-typedef struct PIIX3State {
-    PCIDevice dev;
-} PIIX3State;
-
-PIIX3State *piix3_state;
-
-/* 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 inline int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
-{
-    int slot_addend;
-    slot_addend = (pci_dev->devfn >> 3) - 1;
-    return (irq_num + slot_addend) & 3;
-}
-
-static inline int get_pci_irq_level(int irq_num)
-{
-    int pic_level;
-#if (PCI_IRQ_WORDS == 2)
-    pic_level = ((pci_irq_levels[irq_num][0] | 
-                  pci_irq_levels[irq_num][1]) != 0);
-#else
-    {
-        int i;
-        pic_level = 0;
-        for(i = 0; i < PCI_IRQ_WORDS; i++) {
-            if (pci_irq_levels[irq_num][i]) {
-                pic_level = 1;
-                break;
-            }
-        }
-    }
-#endif
-    return pic_level;
-}
-
-static void piix3_set_irq(PCIDevice *pci_dev, int irq_num, int level)
-{
-    int irq_index, shift, pic_irq, pic_level;
-    uint32_t *p;
-
-    irq_num = pci_slot_get_pirq(pci_dev, irq_num);
-    irq_index = pci_dev->irq_index;
-    p = &pci_irq_levels[irq_num][irq_index >> 5];
-    shift = (irq_index & 0x1f);
-    *p = (*p & ~(1 << shift)) | (level << shift);
-
-    /* now we change the pic irq level according to the piix irq mappings */
-    /* XXX: optimize */
-    pic_irq = piix3_state->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;
-        if (pic_irq == piix3_state->dev.config[0x60])
-            pic_level |= get_pci_irq_level(0);
-        if (pic_irq == piix3_state->dev.config[0x61])
-            pic_level |= get_pci_irq_level(1);
-        if (pic_irq == piix3_state->dev.config[0x62])
-            pic_level |= get_pci_irq_level(2);
-        if (pic_irq == piix3_state->dev.config[0x63])
-            pic_level |= get_pci_irq_level(3);
-        pic_set_irq(pic_irq, pic_level);
-    }
-}
-
-static void piix3_reset(PIIX3State *d)
-{
-    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[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[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;
-}
-
-void piix3_init(PCIBus *bus)
-{
-    PIIX3State *d;
-    uint8_t *pci_conf;
-
-    d = (PIIX3State *)pci_register_device(bus, "PIIX3", sizeof(PIIX3State),
-                                          -1, NULL, NULL);
-    register_savevm("PIIX3", 0, 1, generic_pci_save, generic_pci_load, d);
-
-    piix3_state = d;
-    pci_conf = d->dev.config;
-
-    pci_conf[0x00] = 0x86; // Intel
-    pci_conf[0x01] = 0x80;
-    pci_conf[0x02] = 0x00; // 82371SB PIIX3 PCI-to-ISA bridge (Step A1)
-    pci_conf[0x03] = 0x70;
-    pci_conf[0x0a] = 0x01; // class_sub = PCI_ISA
-    pci_conf[0x0b] = 0x06; // class_base = PCI_bridge
-    pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic
-
-    piix3_reset(d);
-}
-
-/* PREP pci init */
-
-static inline void set_config(PCIBus *s, target_phys_addr_t addr)
-{
-    int devfn, i;
-
-    for(i = 0; i < 11; i++) {
-        if ((addr & (1 << (11 + i))) != 0)
-            break;
-    }
-    devfn = ((addr >> 8) & 7) | (i << 3);
-    s->config_reg = 0x80000000 | (addr & 0xfc) | (devfn << 8);
-}
-
-static void PPC_PCIIO_writeb (void *opaque, target_phys_addr_t addr, uint32_t 
val)
-{
-    PCIBus *s = opaque;
-    set_config(s, addr);
-    pci_data_write(s, addr, val, 1);
-}
-
-static void PPC_PCIIO_writew (void *opaque, target_phys_addr_t addr, uint32_t 
val)
-{
-    PCIBus *s = opaque;
-    set_config(s, addr);
-#ifdef TARGET_WORDS_BIGENDIAN
-    val = bswap16(val);
-#endif
-    pci_data_write(s, addr, val, 2);
-}
-
-static void PPC_PCIIO_writel (void *opaque, target_phys_addr_t addr, uint32_t 
val)
-{
-    PCIBus *s = opaque;
-    set_config(s, addr);
-#ifdef TARGET_WORDS_BIGENDIAN
-    val = bswap32(val);
-#endif
-    pci_data_write(s, addr, val, 4);
-}
-
-static uint32_t PPC_PCIIO_readb (void *opaque, target_phys_addr_t addr)
-{
-    PCIBus *s = opaque;
-    uint32_t val;
-    set_config(s, addr);
-    val = pci_data_read(s, addr, 1);
-    return val;
-}
-
-static uint32_t PPC_PCIIO_readw (void *opaque, target_phys_addr_t addr)
-{
-    PCIBus *s = opaque;
-    uint32_t val;
-    set_config(s, addr);
-    val = pci_data_read(s, addr, 2);
-#ifdef TARGET_WORDS_BIGENDIAN
-    val = bswap16(val);
-#endif
-    return val;
-}
-
-static uint32_t PPC_PCIIO_readl (void *opaque, target_phys_addr_t addr)
-{
-    PCIBus *s = opaque;
-    uint32_t val;
-    set_config(s, addr);
-    val = pci_data_read(s, addr, 4);
-#ifdef TARGET_WORDS_BIGENDIAN
-    val = bswap32(val);
-#endif
-    return val;
-}
-
-static CPUWriteMemoryFunc *PPC_PCIIO_write[] = {
-    &PPC_PCIIO_writeb,
-    &PPC_PCIIO_writew,
-    &PPC_PCIIO_writel,
-};
-
-static CPUReadMemoryFunc *PPC_PCIIO_read[] = {
-    &PPC_PCIIO_readb,
-    &PPC_PCIIO_readw,
-    &PPC_PCIIO_readl,
-};
-
-static void prep_set_irq(PCIDevice *d, int irq_num, int level)
-{
-    /* XXX: we do not simulate the hardware - we rely on the BIOS to
-       set correctly for irq line field */
-    pic_set_irq(d->config[PCI_INTERRUPT_LINE], level);
-}
-
-PCIBus *pci_prep_init(void)
-{
-    PCIBus *s;
-    PCIDevice *d;
-    int PPC_io_memory;
-
-    s = pci_register_bus();
-    s->set_irq = prep_set_irq;
-
-    register_ioport_write(0xcf8, 4, 4, pci_addr_writel, s);
-    register_ioport_read(0xcf8, 4, 4, pci_addr_readl, s);
-
-    register_ioport_write(0xcfc, 4, 1, pci_data_writeb, s);
-    register_ioport_write(0xcfc, 4, 2, pci_data_writew, s);
-    register_ioport_write(0xcfc, 4, 4, pci_data_writel, s);
-    register_ioport_read(0xcfc, 4, 1, pci_data_readb, s);
-    register_ioport_read(0xcfc, 4, 2, pci_data_readw, s);
-    register_ioport_read(0xcfc, 4, 4, pci_data_readl, s);
-
-    PPC_io_memory = cpu_register_io_memory(0, PPC_PCIIO_read, 
-                                           PPC_PCIIO_write, s);
-    cpu_register_physical_memory(0x80800000, 0x00400000, PPC_io_memory);
-
-    /* PCI host bridge */ 
-    d = pci_register_device(s, "PREP Host Bridge - Motorola Raven", 
-                            sizeof(PCIDevice), 0, NULL, NULL);
-    d->config[0x00] = 0x57; // vendor_id : Motorola
-    d->config[0x01] = 0x10;
-    d->config[0x02] = 0x01; // device_id : Raven
-    d->config[0x03] = 0x48;
-    d->config[0x08] = 0x00; // revision
-    d->config[0x0A] = 0x00; // class_sub = pci host
-    d->config[0x0B] = 0x06; // class_base = PCI_bridge
-    d->config[0x0C] = 0x08; // cache_line_size
-    d->config[0x0D] = 0x10; // latency_timer
-    d->config[0x0E] = 0x00; // header_type
-    d->config[0x34] = 0x00; // capabilities_pointer
-
-    return s;
-}
-
-
-/* Grackle PCI host */
-static void pci_grackle_config_writel (void *opaque, target_phys_addr_t addr,
-                                       uint32_t val)
-{
-    PCIBus *s = opaque;
-#ifdef TARGET_WORDS_BIGENDIAN
-    val = bswap32(val);
-#endif
-    s->config_reg = val;
-}
-
-static uint32_t pci_grackle_config_readl (void *opaque, target_phys_addr_t 
addr)
-{
-    PCIBus *s = opaque;
-    uint32_t val;
-
-    val = s->config_reg;
-#ifdef TARGET_WORDS_BIGENDIAN
-    val = bswap32(val);
-#endif
-    return val;
-}
-
-static CPUWriteMemoryFunc *pci_grackle_config_write[] = {
-    &pci_grackle_config_writel,
-    &pci_grackle_config_writel,
-    &pci_grackle_config_writel,
-};
-
-static CPUReadMemoryFunc *pci_grackle_config_read[] = {
-    &pci_grackle_config_readl,
-    &pci_grackle_config_readl,
-    &pci_grackle_config_readl,
-};
-
-static void pci_grackle_writeb (void *opaque, target_phys_addr_t addr,
-                                uint32_t val)
-{
-    PCIBus *s = opaque;
-    pci_data_write(s, addr, val, 1);
-}
-
-static void pci_grackle_writew (void *opaque, target_phys_addr_t addr,
-                                uint32_t val)
-{
-    PCIBus *s = opaque;
-#ifdef TARGET_WORDS_BIGENDIAN
-    val = bswap16(val);
-#endif
-    pci_data_write(s, addr, val, 2);
-}
-
-static void pci_grackle_writel (void *opaque, target_phys_addr_t addr,
-                                uint32_t val)
-{
-    PCIBus *s = opaque;
-#ifdef TARGET_WORDS_BIGENDIAN
-    val = bswap32(val);
-#endif
-    pci_data_write(s, addr, val, 4);
-}
-
-static uint32_t pci_grackle_readb (void *opaque, target_phys_addr_t addr)
-{
-    PCIBus *s = opaque;
-    uint32_t val;
-    val = pci_data_read(s, addr, 1);
-    return val;
-}
-
-static uint32_t pci_grackle_readw (void *opaque, target_phys_addr_t addr)
-{
-    PCIBus *s = opaque;
-    uint32_t val;
-    val = pci_data_read(s, addr, 2);
-#ifdef TARGET_WORDS_BIGENDIAN
-    val = bswap16(val);
-#endif
-    return val;
-}
-
-static uint32_t pci_grackle_readl (void *opaque, target_phys_addr_t addr)
-{
-    PCIBus *s = opaque;
-    uint32_t val;
-
-    val = pci_data_read(s, addr, 4);
-#ifdef TARGET_WORDS_BIGENDIAN
-    val = bswap32(val);
-#endif
-    return val;
-}
-
-static CPUWriteMemoryFunc *pci_grackle_write[] = {
-    &pci_grackle_writeb,
-    &pci_grackle_writew,
-    &pci_grackle_writel,
-};
-
-static CPUReadMemoryFunc *pci_grackle_read[] = {
-    &pci_grackle_readb,
-    &pci_grackle_readw,
-    &pci_grackle_readl,
-};
-
-void pci_set_pic(PCIBus *bus, SetIRQFunc *set_irq, void *irq_opaque)
-{
-    bus->low_set_irq = set_irq;
-    bus->irq_opaque = irq_opaque;
-}
-
-/* XXX: we do not simulate the hardware - we rely on the BIOS to
-   set correctly for irq line field */
-static void pci_set_irq_simple(PCIDevice *d, int irq_num, int level)
-{
-    PCIBus *s = d->bus;
-    s->low_set_irq(s->irq_opaque, d->config[PCI_INTERRUPT_LINE], level);
-}
-
-PCIBus *pci_grackle_init(uint32_t base)
-{
-    PCIBus *s;
-    PCIDevice *d;
-    int pci_mem_config, pci_mem_data;
-
-    s = pci_register_bus();
-    s->set_irq = pci_set_irq_simple;
-
-    pci_mem_config = cpu_register_io_memory(0, pci_grackle_config_read, 
-                                            pci_grackle_config_write, s);
-    pci_mem_data = cpu_register_io_memory(0, pci_grackle_read,
-                                          pci_grackle_write, s);
-    cpu_register_physical_memory(base, 0x1000, pci_mem_config);
-    cpu_register_physical_memory(base + 0x00200000, 0x1000, pci_mem_data);
-    d = pci_register_device(s, "Grackle host bridge", sizeof(PCIDevice), 
-                            0, NULL, NULL);
-    d->config[0x00] = 0x57; // vendor_id
-    d->config[0x01] = 0x10;
-    d->config[0x02] = 0x02; // device_id
-    d->config[0x03] = 0x00;
-    d->config[0x08] = 0x00; // revision
-    d->config[0x09] = 0x01;
-    d->config[0x0a] = 0x00; // class_sub = host
-    d->config[0x0b] = 0x06; // class_base = PCI_bridge
-    d->config[0x0e] = 0x00; // header_type
-
-    d->config[0x18] = 0x00;  // primary_bus
-    d->config[0x19] = 0x01;  // secondary_bus
-    d->config[0x1a] = 0x00;  // subordinate_bus
-    d->config[0x1c] = 0x00;
-    d->config[0x1d] = 0x00;
-    
-    d->config[0x20] = 0x00; // memory_base
-    d->config[0x21] = 0x00;
-    d->config[0x22] = 0x01; // memory_limit
-    d->config[0x23] = 0x00;
-    
-    d->config[0x24] = 0x00; // prefetchable_memory_base
-    d->config[0x25] = 0x00;
-    d->config[0x26] = 0x00; // prefetchable_memory_limit
-    d->config[0x27] = 0x00;
-
-#if 0
-    /* PCI2PCI bridge same values as PearPC - check this */
-    d->config[0x00] = 0x11; // vendor_id
-    d->config[0x01] = 0x10;
-    d->config[0x02] = 0x26; // device_id
-    d->config[0x03] = 0x00;
-    d->config[0x08] = 0x02; // revision
-    d->config[0x0a] = 0x04; // class_sub = pci2pci
-    d->config[0x0b] = 0x06; // class_base = PCI_bridge
-    d->config[0x0e] = 0x01; // header_type
-
-    d->config[0x18] = 0x0;  // primary_bus
-    d->config[0x19] = 0x1;  // secondary_bus
-    d->config[0x1a] = 0x1;  // subordinate_bus
-    d->config[0x1c] = 0x10; // io_base
-    d->config[0x1d] = 0x20; // io_limit
-    
-    d->config[0x20] = 0x80; // memory_base
-    d->config[0x21] = 0x80;
-    d->config[0x22] = 0x90; // memory_limit
-    d->config[0x23] = 0x80;
-    
-    d->config[0x24] = 0x00; // prefetchable_memory_base
-    d->config[0x25] = 0x84;
-    d->config[0x26] = 0x00; // prefetchable_memory_limit
-    d->config[0x27] = 0x85;
-#endif
-    return s;
-}
-
-/* Uninorth PCI host (for all Mac99 and newer machines */
-static void pci_unin_main_config_writel (void *opaque, target_phys_addr_t addr,
-                                         uint32_t val)
-{
-    PCIBus *s = opaque;
-    int i;
-
-#ifdef TARGET_WORDS_BIGENDIAN
-    val = bswap32(val);
-#endif
-
-    for (i = 11; i < 32; i++) {
-        if ((val & (1 << i)) != 0)
-            break;
-    }
-#if 0
-    s->config_reg = 0x80000000 | (1 << 16) | (val & 0x7FC) | (i << 11);
-#else
-    s->config_reg = 0x80000000 | (0 << 16) | (val & 0x7FC) | (i << 11);
-#endif
-}
-
-static uint32_t pci_unin_main_config_readl (void *opaque,
-                                            target_phys_addr_t addr)
-{
-    PCIBus *s = opaque;
-    uint32_t val;
-    int devfn;
-
-    devfn = (s->config_reg >> 8) & 0xFF;
-    val = (1 << (devfn >> 3)) | ((devfn & 0x07) << 8) | (s->config_reg & 0xFC);
-#ifdef TARGET_WORDS_BIGENDIAN
-    val = bswap32(val);
-#endif
-
-    return val;
-}
-
-static CPUWriteMemoryFunc *pci_unin_main_config_write[] = {
-    &pci_unin_main_config_writel,
-    &pci_unin_main_config_writel,
-    &pci_unin_main_config_writel,
-};
-
-static CPUReadMemoryFunc *pci_unin_main_config_read[] = {
-    &pci_unin_main_config_readl,
-    &pci_unin_main_config_readl,
-    &pci_unin_main_config_readl,
-};
-
-static void pci_unin_main_writeb (void *opaque, target_phys_addr_t addr,
-                                  uint32_t val)
-{
-    PCIBus *s = opaque;
-    pci_data_write(s, addr & 7, val, 1);
-}
-
-static void pci_unin_main_writew (void *opaque, target_phys_addr_t addr,
-                                  uint32_t val)
-{
-    PCIBus *s = opaque;
-#ifdef TARGET_WORDS_BIGENDIAN
-    val = bswap16(val);
-#endif
-    pci_data_write(s, addr & 7, val, 2);
-}
-
-static void pci_unin_main_writel (void *opaque, target_phys_addr_t addr,
-                                uint32_t val)
-{
-    PCIBus *s = opaque;
-#ifdef TARGET_WORDS_BIGENDIAN
-    val = bswap32(val);
-#endif
-    pci_data_write(s, addr & 7, val, 4);
-}
-
-static uint32_t pci_unin_main_readb (void *opaque, target_phys_addr_t addr)
-{
-    PCIBus *s = opaque;
-    uint32_t val;
-
-    val = pci_data_read(s, addr & 7, 1);
-
-    return val;
-}
-
-static uint32_t pci_unin_main_readw (void *opaque, target_phys_addr_t addr)
-{
-    PCIBus *s = opaque;
-    uint32_t val;
-
-    val = pci_data_read(s, addr & 7, 2);
-#ifdef TARGET_WORDS_BIGENDIAN
-    val = bswap16(val);
-#endif
-
-    return val;
-}
-
-static uint32_t pci_unin_main_readl (void *opaque, target_phys_addr_t addr)
-{
-    PCIBus *s = opaque;
-    uint32_t val;
-
-    val = pci_data_read(s, addr, 4);
-#ifdef TARGET_WORDS_BIGENDIAN
-    val = bswap32(val);
-#endif
-
-    return val;
-}
-
-static CPUWriteMemoryFunc *pci_unin_main_write[] = {
-    &pci_unin_main_writeb,
-    &pci_unin_main_writew,
-    &pci_unin_main_writel,
-};
-
-static CPUReadMemoryFunc *pci_unin_main_read[] = {
-    &pci_unin_main_readb,
-    &pci_unin_main_readw,
-    &pci_unin_main_readl,
-};
-
-#if 0
-
-static void pci_unin_config_writel (void *opaque, target_phys_addr_t addr,
-                                    uint32_t val)
-{
-    PCIBus *s = opaque;
-
-#ifdef TARGET_WORDS_BIGENDIAN
-    val = bswap32(val);
-#endif
-    s->config_reg = 0x80000000 | (val & ~0x00000001);
-}
-
-static uint32_t pci_unin_config_readl (void *opaque,
-                                       target_phys_addr_t addr)
-{
-    PCIBus *s = opaque;
-    uint32_t val;
-
-    val = (s->config_reg | 0x00000001) & ~0x80000000;
-#ifdef TARGET_WORDS_BIGENDIAN
-    val = bswap32(val);
-#endif
-
-    return val;
-}
-
-static CPUWriteMemoryFunc *pci_unin_config_write[] = {
-    &pci_unin_config_writel,
-    &pci_unin_config_writel,
-    &pci_unin_config_writel,
-};
-
-static CPUReadMemoryFunc *pci_unin_config_read[] = {
-    &pci_unin_config_readl,
-    &pci_unin_config_readl,
-    &pci_unin_config_readl,
-};
-
-static void pci_unin_writeb (void *opaque, target_phys_addr_t addr,
-                             uint32_t val)
-{
-    PCIBus *s = opaque;
-    pci_data_write(s, addr & 3, val, 1);
-}
-
-static void pci_unin_writew (void *opaque, target_phys_addr_t addr,
-                             uint32_t val)
-{
-    PCIBus *s = opaque;
-#ifdef TARGET_WORDS_BIGENDIAN
-    val = bswap16(val);
-#endif
-    pci_data_write(s, addr & 3, val, 2);
-}
-
-static void pci_unin_writel (void *opaque, target_phys_addr_t addr,
-                             uint32_t val)
-{
-    PCIBus *s = opaque;
-#ifdef TARGET_WORDS_BIGENDIAN
-    val = bswap32(val);
-#endif
-    pci_data_write(s, addr & 3, val, 4);
-}
-
-static uint32_t pci_unin_readb (void *opaque, target_phys_addr_t addr)
-{
-    PCIBus *s = opaque;
-    uint32_t val;
-
-    val = pci_data_read(s, addr & 3, 1);
-
-    return val;
-}
-
-static uint32_t pci_unin_readw (void *opaque, target_phys_addr_t addr)
-{
-    PCIBus *s = opaque;
-    uint32_t val;
-
-    val = pci_data_read(s, addr & 3, 2);
-#ifdef TARGET_WORDS_BIGENDIAN
-    val = bswap16(val);
-#endif
-
-    return val;
-}
-
-static uint32_t pci_unin_readl (void *opaque, target_phys_addr_t addr)
-{
-    PCIBus *s = opaque;
-    uint32_t val;
-
-    val = pci_data_read(s, addr & 3, 4);
-#ifdef TARGET_WORDS_BIGENDIAN
-    val = bswap32(val);
-#endif
-
-    return val;
-}
-
-static CPUWriteMemoryFunc *pci_unin_write[] = {
-    &pci_unin_writeb,
-    &pci_unin_writew,
-    &pci_unin_writel,
-};
-
-static CPUReadMemoryFunc *pci_unin_read[] = {
-    &pci_unin_readb,
-    &pci_unin_readw,
-    &pci_unin_readl,
-};
-#endif
-
-PCIBus *pci_pmac_init(void)
-{
-    PCIBus *s;
-    PCIDevice *d;
-    int pci_mem_config, pci_mem_data;
-
-    /* Use values found on a real PowerMac */
-    /* Uninorth main bus */
-    s = pci_register_bus();
-    s->set_irq = pci_set_irq_simple;
-
-    pci_mem_config = cpu_register_io_memory(0, pci_unin_main_config_read, 
-                                            pci_unin_main_config_write, s);
-    pci_mem_data = cpu_register_io_memory(0, pci_unin_main_read,
-                                          pci_unin_main_write, s);
-    cpu_register_physical_memory(0xf2800000, 0x1000, pci_mem_config);
-    cpu_register_physical_memory(0xf2c00000, 0x1000, pci_mem_data);
-    s->devfn_min = 11 << 3;
-    d = pci_register_device(s, "Uni-north main", sizeof(PCIDevice), 
-                            11 << 3, NULL, NULL);
-    d->config[0x00] = 0x6b; // vendor_id : Apple
-    d->config[0x01] = 0x10;
-    d->config[0x02] = 0x1F; // device_id
-    d->config[0x03] = 0x00;
-    d->config[0x08] = 0x00; // revision
-    d->config[0x0A] = 0x00; // class_sub = pci host
-    d->config[0x0B] = 0x06; // class_base = PCI_bridge
-    d->config[0x0C] = 0x08; // cache_line_size
-    d->config[0x0D] = 0x10; // latency_timer
-    d->config[0x0E] = 0x00; // header_type
-    d->config[0x34] = 0x00; // capabilities_pointer
-
-#if 0 // XXX: not activated as PPC BIOS doesn't handle mutiple buses properly
-    /* pci-to-pci bridge */
-    d = pci_register_device("Uni-north bridge", sizeof(PCIDevice), 0, 13 << 3,
-                            NULL, NULL);
-    d->config[0x00] = 0x11; // vendor_id : TI
-    d->config[0x01] = 0x10;
-    d->config[0x02] = 0x26; // device_id
-    d->config[0x03] = 0x00;
-    d->config[0x08] = 0x05; // revision
-    d->config[0x0A] = 0x04; // class_sub = pci2pci
-    d->config[0x0B] = 0x06; // class_base = PCI_bridge
-    d->config[0x0C] = 0x08; // cache_line_size
-    d->config[0x0D] = 0x20; // latency_timer
-    d->config[0x0E] = 0x01; // header_type
-
-    d->config[0x18] = 0x01; // primary_bus
-    d->config[0x19] = 0x02; // secondary_bus
-    d->config[0x1A] = 0x02; // subordinate_bus
-    d->config[0x1B] = 0x20; // secondary_latency_timer
-    d->config[0x1C] = 0x11; // io_base
-    d->config[0x1D] = 0x01; // io_limit
-    d->config[0x20] = 0x00; // memory_base
-    d->config[0x21] = 0x80;
-    d->config[0x22] = 0x00; // memory_limit
-    d->config[0x23] = 0x80;
-    d->config[0x24] = 0x01; // prefetchable_memory_base
-    d->config[0x25] = 0x80;
-    d->config[0x26] = 0xF1; // prefectchable_memory_limit
-    d->config[0x27] = 0x7F;
-    // d->config[0x34] = 0xdc // capabilities_pointer
-#endif
-#if 0 // XXX: not needed for now
-    /* Uninorth AGP bus */
-    s = &pci_bridge[1];
-    pci_mem_config = cpu_register_io_memory(0, pci_unin_config_read, 
-                                            pci_unin_config_write, s);
-    pci_mem_data = cpu_register_io_memory(0, pci_unin_read,
-                                          pci_unin_write, s);
-    cpu_register_physical_memory(0xf0800000, 0x1000, pci_mem_config);
-    cpu_register_physical_memory(0xf0c00000, 0x1000, pci_mem_data);
-
-    d = pci_register_device("Uni-north AGP", sizeof(PCIDevice), 0, 11 << 3,
-                            NULL, NULL);
-    d->config[0x00] = 0x6b; // vendor_id : Apple
-    d->config[0x01] = 0x10;
-    d->config[0x02] = 0x20; // device_id
-    d->config[0x03] = 0x00;
-    d->config[0x08] = 0x00; // revision
-    d->config[0x0A] = 0x00; // class_sub = pci host
-    d->config[0x0B] = 0x06; // class_base = PCI_bridge
-    d->config[0x0C] = 0x08; // cache_line_size
-    d->config[0x0D] = 0x10; // latency_timer
-    d->config[0x0E] = 0x00; // header_type
-    //    d->config[0x34] = 0x80; // capabilities_pointer
-#endif
-
-#if 0 // XXX: not needed for now
-    /* Uninorth internal bus */
-    s = &pci_bridge[2];
-    pci_mem_config = cpu_register_io_memory(0, pci_unin_config_read, 
-                                            pci_unin_config_write, s);
-    pci_mem_data = cpu_register_io_memory(0, pci_unin_read,
-                                          pci_unin_write, s);
-    cpu_register_physical_memory(0xf4800000, 0x1000, pci_mem_config);
-    cpu_register_physical_memory(0xf4c00000, 0x1000, pci_mem_data);
-
-    d = pci_register_device("Uni-north internal", sizeof(PCIDevice),
-                            3, 11 << 3, NULL, NULL);
-    d->config[0x00] = 0x6b; // vendor_id : Apple
-    d->config[0x01] = 0x10;
-    d->config[0x02] = 0x1E; // device_id
-    d->config[0x03] = 0x00;
-    d->config[0x08] = 0x00; // revision
-    d->config[0x0A] = 0x00; // class_sub = pci host
-    d->config[0x0B] = 0x06; // class_base = PCI_bridge
-    d->config[0x0C] = 0x08; // cache_line_size
-    d->config[0x0D] = 0x10; // latency_timer
-    d->config[0x0E] = 0x00; // header_type
-    d->config[0x34] = 0x00; // capabilities_pointer
-#endif
-    return s;
-}
-
-/* Ultrasparc APB PCI host */
-static void pci_apb_config_writel (void *opaque, target_phys_addr_t addr,
-                                         uint32_t val)
-{
-    PCIBus *s = opaque;
-    int i;
-
-    for (i = 11; i < 32; i++) {
-        if ((val & (1 << i)) != 0)
-            break;
-    }
-    s->config_reg = 0x80000000 | (1 << 16) | (val & 0x7FC) | (i << 11);
-}
-
-static uint32_t pci_apb_config_readl (void *opaque,
-                                            target_phys_addr_t addr)
-{
-    PCIBus *s = opaque;
-    uint32_t val;
-    int devfn;
-
-    devfn = (s->config_reg >> 8) & 0xFF;
-    val = (1 << (devfn >> 3)) | ((devfn & 0x07) << 8) | (s->config_reg & 0xFC);
-    return val;
-}
-
-static CPUWriteMemoryFunc *pci_apb_config_write[] = {
-    &pci_apb_config_writel,
-    &pci_apb_config_writel,
-    &pci_apb_config_writel,
-};
-
-static CPUReadMemoryFunc *pci_apb_config_read[] = {
-    &pci_apb_config_readl,
-    &pci_apb_config_readl,
-    &pci_apb_config_readl,
-};
-
-static void apb_config_writel (void *opaque, target_phys_addr_t addr,
-                              uint32_t val)
-{
-    //PCIBus *s = opaque;
-
-    switch (addr & 0x3f) {
-    case 0x00: // Control/Status
-    case 0x10: // AFSR
-    case 0x18: // AFAR
-    case 0x20: // Diagnostic
-    case 0x28: // Target address space
-       // XXX
-    default:
-       break;
-    }
-}
-
-static uint32_t apb_config_readl (void *opaque,
-                                 target_phys_addr_t addr)
-{
-    //PCIBus *s = opaque;
-    uint32_t val;
-
-    switch (addr & 0x3f) {
-    case 0x00: // Control/Status
-    case 0x10: // AFSR
-    case 0x18: // AFAR
-    case 0x20: // Diagnostic
-    case 0x28: // Target address space
-       // XXX
-    default:
-       val = 0;
-       break;
-    }
-    return val;
-}
-
-static CPUWriteMemoryFunc *apb_config_write[] = {
-    &apb_config_writel,
-    &apb_config_writel,
-    &apb_config_writel,
-};
-
-static CPUReadMemoryFunc *apb_config_read[] = {
-    &apb_config_readl,
-    &apb_config_readl,
-    &apb_config_readl,
-};
-
-static void pci_apb_writeb (void *opaque, target_phys_addr_t addr,
-                                  uint32_t val)
-{
-    PCIBus *s = opaque;
-
-    pci_data_write(s, addr & 7, val, 1);
-}
-
-static void pci_apb_writew (void *opaque, target_phys_addr_t addr,
-                                  uint32_t val)
-{
-    PCIBus *s = opaque;
-
-    pci_data_write(s, addr & 7, val, 2);
-}
-
-static void pci_apb_writel (void *opaque, target_phys_addr_t addr,
-                                uint32_t val)
-{
-    PCIBus *s = opaque;
-
-    pci_data_write(s, addr & 7, val, 4);
-}
-
-static uint32_t pci_apb_readb (void *opaque, target_phys_addr_t addr)
-{
-    PCIBus *s = opaque;
-    uint32_t val;
-
-    val = pci_data_read(s, addr & 7, 1);
-    return val;
-}
-
-static uint32_t pci_apb_readw (void *opaque, target_phys_addr_t addr)
-{
-    PCIBus *s = opaque;
-    uint32_t val;
-
-    val = pci_data_read(s, addr & 7, 2);
-    return val;
-}
-
-static uint32_t pci_apb_readl (void *opaque, target_phys_addr_t addr)
-{
-    PCIBus *s = opaque;
-    uint32_t val;
-
-    val = pci_data_read(s, addr, 4);
-    return val;
-}
-
-static CPUWriteMemoryFunc *pci_apb_write[] = {
-    &pci_apb_writeb,
-    &pci_apb_writew,
-    &pci_apb_writel,
-};
-
-static CPUReadMemoryFunc *pci_apb_read[] = {
-    &pci_apb_readb,
-    &pci_apb_readw,
-    &pci_apb_readl,
-};
-
-static void pci_apb_iowriteb (void *opaque, target_phys_addr_t addr,
-                                  uint32_t val)
-{
-    cpu_outb(NULL, addr & 0xffff, val);
-}
-
-static void pci_apb_iowritew (void *opaque, target_phys_addr_t addr,
-                                  uint32_t val)
-{
-    cpu_outw(NULL, addr & 0xffff, val);
-}
-
-static void pci_apb_iowritel (void *opaque, target_phys_addr_t addr,
-                                uint32_t val)
-{
-    cpu_outl(NULL, addr & 0xffff, val);
-}
-
-static uint32_t pci_apb_ioreadb (void *opaque, target_phys_addr_t addr)
-{
-    uint32_t val;
-
-    val = cpu_inb(NULL, addr & 0xffff);
-    return val;
-}
-
-static uint32_t pci_apb_ioreadw (void *opaque, target_phys_addr_t addr)
-{
-    uint32_t val;
-
-    val = cpu_inw(NULL, addr & 0xffff);
-    return val;
-}
-
-static uint32_t pci_apb_ioreadl (void *opaque, target_phys_addr_t addr)
-{
-    uint32_t val;
-
-    val = cpu_inl(NULL, addr & 0xffff);
-    return val;
-}
-
-static CPUWriteMemoryFunc *pci_apb_iowrite[] = {
-    &pci_apb_iowriteb,
-    &pci_apb_iowritew,
-    &pci_apb_iowritel,
-};
-
-static CPUReadMemoryFunc *pci_apb_ioread[] = {
-    &pci_apb_ioreadb,
-    &pci_apb_ioreadw,
-    &pci_apb_ioreadl,
-};
-
-PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base)
-{
-    PCIBus *s;
-    PCIDevice *d;
-    int pci_mem_config, pci_mem_data, apb_config, pci_ioport;
-
-    /* Ultrasparc APB main bus */
-    s = pci_register_bus();
-    s->set_irq = pci_set_irq_simple;
-
-    pci_mem_config = cpu_register_io_memory(0, pci_apb_config_read,
-                                            pci_apb_config_write, s);
-    apb_config = cpu_register_io_memory(0, apb_config_read,
-                                       apb_config_write, s);
-    pci_mem_data = cpu_register_io_memory(0, pci_apb_read,
-                                          pci_apb_write, s);
-    pci_ioport = cpu_register_io_memory(0, pci_apb_ioread,
-                                          pci_apb_iowrite, s);
-
-    cpu_register_physical_memory(special_base + 0x2000ULL, 0x40, apb_config);
-    cpu_register_physical_memory(special_base + 0x1000000ULL, 0x10, 
pci_mem_config);
-    cpu_register_physical_memory(special_base + 0x2000000ULL, 0x10000, 
pci_ioport);
-    cpu_register_physical_memory(mem_base, 0x10000000, pci_mem_data); // XXX 
size should be 4G-prom
-
-    d = pci_register_device(s, "Advanced PCI Bus", sizeof(PCIDevice), 
-                            -1, NULL, NULL);
-    d->config[0x00] = 0x8e; // vendor_id : Sun
-    d->config[0x01] = 0x10;
-    d->config[0x02] = 0x00; // device_id
-    d->config[0x03] = 0xa0;
-    d->config[0x04] = 0x06; // command = bus master, pci mem
-    d->config[0x05] = 0x00;
-    d->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
-    d->config[0x07] = 0x03; // status = medium devsel
-    d->config[0x08] = 0x00; // revision
-    d->config[0x09] = 0x00; // programming i/f
-    d->config[0x0A] = 0x00; // class_sub = pci host
-    d->config[0x0B] = 0x06; // class_base = PCI_bridge
-    d->config[0x0D] = 0x10; // latency_timer
-    d->config[0x0E] = 0x00; // header_type
-    return s;
-}
-
 /***********************************************************/
 /* generic PCI irq support */
 
@@ -1547,34 +403,46 @@ void pci_set_irq(PCIDevice *pci_dev, int
 void pci_set_irq(PCIDevice *pci_dev, int irq_num, int level)
 {
     PCIBus *bus = pci_dev->bus;
-    bus->set_irq(pci_dev, irq_num, level);
+    bus->set_irq(pci_dev, bus->irq_opaque, irq_num, level);
 }
 
 /***********************************************************/
 /* monitor info on PCI */
 
+typedef struct {
+    uint16_t class;
+    const char *desc;
+} pci_class_desc;
+
+static pci_class_desc pci_class_descriptions[] = 
+{
+    { 0x0101, "IDE controller"},
+    { 0x0200, "Ethernet controller"},
+    { 0x0300, "VGA controller"},
+    { 0x0600, "Host bridge"},
+    { 0x0601, "ISA bridge"},
+    { 0x0604, "PCI bridge"},
+    { 0x0c03, "USB controller"},
+    { 0, NULL}
+};
+
 static void pci_info_device(PCIDevice *d)
 {
     int i, class;
     PCIIORegion *r;
+    pci_class_desc *desc;
 
     term_printf("  Bus %2d, device %3d, function %d:\n",
            d->bus->bus_num, d->devfn >> 3, d->devfn & 7);
     class = le16_to_cpu(*((uint16_t *)(d->config + PCI_CLASS_DEVICE)));
     term_printf("    ");
-    switch(class) {
-    case 0x0101:
-        term_printf("IDE controller");
-        break;
-    case 0x0200:
-        term_printf("Ethernet controller");
-        break;
-    case 0x0300:
-        term_printf("VGA controller");
-        break;
-    default:
+    desc = pci_class_descriptions;
+    while (desc->desc && class != desc->class)
+        desc++;
+    if (desc->desc) {
+        term_printf("%s", desc->desc);
+    } else {
         term_printf("Class %04x", class);
-        break;
     }
     term_printf(": PCI device %04x:%04x\n",
            le16_to_cpu(*((uint16_t *)(d->config + PCI_VENDOR_ID))),
@@ -1598,7 +466,7 @@ static void pci_info_device(PCIDevice *d
     }
 }
 
-void pci_info(void)
+void pci_for_each_device(void (*fn)(PCIDevice *d))
 {
     PCIBus *bus = first_bus;
     PCIDevice *d;
@@ -1608,253 +476,14 @@ void pci_info(void)
         for(devfn = 0; devfn < 256; devfn++) {
             d = bus->devices[devfn];
             if (d)
-                pci_info_device(d);
-        }
-    }
-}
-
-/***********************************************************/
-/* XXX: the following should be moved to the PC BIOS */
-
-static __attribute__((unused)) uint32_t isa_inb(uint32_t addr)
-{
-    return cpu_inb(NULL, addr);
-}
-
-static void isa_outb(uint32_t val, uint32_t addr)
-{
-    cpu_outb(NULL, addr, val);
-}
-
-static __attribute__((unused)) uint32_t isa_inw(uint32_t addr)
-{
-    return cpu_inw(NULL, addr);
-}
-
-static __attribute__((unused)) void isa_outw(uint32_t val, uint32_t addr)
-{
-    cpu_outw(NULL, addr, val);
-}
-
-static __attribute__((unused)) uint32_t isa_inl(uint32_t addr)
-{
-    return cpu_inl(NULL, addr);
-}
-
-static __attribute__((unused)) void isa_outl(uint32_t val, uint32_t addr)
-{
-    cpu_outl(NULL, addr, val);
-}
-
-static void pci_config_writel(PCIDevice *d, uint32_t addr, uint32_t val)
-{
-    PCIBus *s = d->bus;
-    s->config_reg = 0x80000000 | (s->bus_num << 16) | 
-        (d->devfn << 8) | addr;
-    pci_data_write(s, 0, val, 4);
-}
-
-static void pci_config_writew(PCIDevice *d, uint32_t addr, uint32_t val)
-{
-    PCIBus *s = d->bus;
-    s->config_reg = 0x80000000 | (s->bus_num << 16) | 
-        (d->devfn << 8) | (addr & ~3);
-    pci_data_write(s, addr & 3, val, 2);
-}
-
-static void pci_config_writeb(PCIDevice *d, uint32_t addr, uint32_t val)
-{
-    PCIBus *s = d->bus;
-    s->config_reg = 0x80000000 | (s->bus_num << 16) | 
-        (d->devfn << 8) | (addr & ~3);
-    pci_data_write(s, addr & 3, val, 1);
-}
-
-static __attribute__((unused)) uint32_t pci_config_readl(PCIDevice *d, 
uint32_t addr)
-{
-    PCIBus *s = d->bus;
-    s->config_reg = 0x80000000 | (s->bus_num << 16) | 
-        (d->devfn << 8) | addr;
-    return pci_data_read(s, 0, 4);
-}
-
-static uint32_t pci_config_readw(PCIDevice *d, uint32_t addr)
-{
-    PCIBus *s = d->bus;
-    s->config_reg = 0x80000000 | (s->bus_num << 16) | 
-        (d->devfn << 8) | (addr & ~3);
-    return pci_data_read(s, addr & 3, 2);
-}
-
-static uint32_t pci_config_readb(PCIDevice *d, uint32_t addr)
-{
-    PCIBus *s = d->bus;
-    s->config_reg = 0x80000000 | (s->bus_num << 16) | 
-        (d->devfn << 8) | (addr & ~3);
-    return pci_data_read(s, addr & 3, 1);
-}
-
-static uint32_t pci_bios_io_addr;
-static uint32_t pci_bios_mem_addr;
-/* host irqs corresponding to PCI irqs A-D */
-static uint8_t pci_irqs[4] = { 10, 11, 10, 11 };
-
-static void pci_set_io_region_addr(PCIDevice *d, int region_num, uint32_t addr)
-{
-    PCIIORegion *r;
-    uint16_t cmd;
-    uint32_t ofs;
-
-    if ( region_num == PCI_ROM_SLOT ) {
-        ofs = 0x30;
-    }else{
-        ofs = 0x10 + region_num * 4;
-    }
-
-    pci_config_writel(d, ofs, addr);
-    r = &d->io_regions[region_num];
-
-    /* enable memory mappings */
-    cmd = pci_config_readw(d, PCI_COMMAND);
-    if ( region_num == PCI_ROM_SLOT )
-        cmd |= 2;
-    else if (r->type & PCI_ADDRESS_SPACE_IO)
-        cmd |= 1;
-    else
-        cmd |= 2;
-    pci_config_writew(d, PCI_COMMAND, cmd);
-}
-
-static void pci_bios_init_device(PCIDevice *d)
-{
-    int class;
-    PCIIORegion *r;
-    uint32_t *paddr;
-    int i, pin, pic_irq, vendor_id, device_id;
-
-    class = pci_config_readw(d, PCI_CLASS_DEVICE);
-    vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
-    device_id = pci_config_readw(d, PCI_DEVICE_ID);
-    switch(class) {
-    case 0x0101:
-        if (vendor_id == 0x8086 && device_id == 0x7010) {
-            /* PIIX3 IDE */
-            pci_config_writew(d, 0x40, 0x8000); // enable IDE0
-            pci_config_writew(d, 0x42, 0x8000); // enable IDE1
-            goto default_map;
-        } else {
-            /* IDE: we map it as in ISA mode */
-            pci_set_io_region_addr(d, 0, 0x1f0);
-            pci_set_io_region_addr(d, 1, 0x3f4);
-            pci_set_io_region_addr(d, 2, 0x170);
-            pci_set_io_region_addr(d, 3, 0x374);
-        }
-        break;
-       case 0x0680:
-       if (vendor_id == 0x8086 && device_id == 0x7113) {
-          // PIIX4 ACPI PM 
-        pci_config_writew(d, 0x20, 0x0000); // NO smb bus IO enable in PIIX4
-        pci_config_writew(d, 0x22, 0x0000); 
-        goto default_map;
-       }
-         break;
-
-    case 0x0300:
-        if (vendor_id != 0x1234)
-            goto default_map;
-        /* VGA: map frame buffer to default Bochs VBE address */
-        pci_set_io_region_addr(d, 0, 0xE0000000);
-        break;
-
-    case 0x0800:
-        /* PIC */
-        vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
-        device_id = pci_config_readw(d, PCI_DEVICE_ID);
-        if (vendor_id == 0x1014) {
-            /* IBM */
-            if (device_id == 0x0046 || device_id == 0xFFFF) {
-                /* MPIC & MPIC2 */
-                pci_set_io_region_addr(d, 0, 0x80800000 + 0x00040000);
-            }
-        }
-        break;
-    case 0xff00:
-        if (vendor_id == 0x0106b &&
-            (device_id == 0x0017 || device_id == 0x0022)) {
-            /* macio bridge */
-            pci_set_io_region_addr(d, 0, 0x80800000);
-        }
-        break;
-    default:
-    default_map:
-        /* default memory mappings */
-        for(i = 0; i < PCI_NUM_REGIONS; i++) {
-            r = &d->io_regions[i];
-            if (r->size) {
-                if (r->type & PCI_ADDRESS_SPACE_IO)
-                    paddr = &pci_bios_io_addr;
-                else
-                    paddr = &pci_bios_mem_addr;
-                *paddr = (*paddr + r->size - 1) & ~(r->size - 1);
-                pci_set_io_region_addr(d, i, *paddr);
-                *paddr += r->size;
-            }
-        }
-        break;
-    }
-
-    /* map the interrupt */
-    pin = pci_config_readb(d, PCI_INTERRUPT_PIN);
-    if (pin != 0) {
-        pin = pci_slot_get_pirq(d, pin - 1);
-        pic_irq = pci_irqs[pin];
-        pci_config_writeb(d, PCI_INTERRUPT_LINE, pic_irq);
-    }
-    if (class== 0x0680&& vendor_id == 0x8086 && device_id == 0x7113) {
-         // PIIX4 ACPI PM
-       pci_config_writew(d, 0x20, 0x0000); // NO smb bus IO enable in PIIX4
-       pci_config_writew(d, 0x22, 0x0000);
-       pci_config_writew(d, 0x3c, 0x0009); // Hardcodeed IRQ9
-       pci_config_writew(d, 0x3d, 0x0001);
-    }
-}
-
-/*
- * This function initializes the PCI devices as a normal PCI BIOS
- * would do. It is provided just in case the BIOS has no support for
- * PCI.
- */
-void pci_bios_init(void)
-{
-    PCIBus *bus;
-    PCIDevice *d;
-    int devfn, i, irq;
-    uint8_t elcr[2];
-
-    pci_bios_io_addr = 0xc000;
-    pci_bios_mem_addr = 0xf0000000;
-
-    /* activate IRQ mappings */
-    elcr[0] = 0x00;
-    elcr[1] = 0x00;
-    for(i = 0; i < 4; i++) {
-        irq = pci_irqs[i];
-        /* set to trigger level */
-        elcr[irq >> 3] |= (1 << (irq & 7));
-        /* activate irq remapping in PIIX */
-        pci_config_writeb((PCIDevice *)piix3_state, 0x60 + i, irq);
-    }
-    isa_outb(elcr[0], 0x4d0);
-    isa_outb(elcr[1], 0x4d1);
-
-    bus = first_bus;
-    if (bus) {
-        for(devfn = 0; devfn < 256; devfn++) {
-            d = bus->devices[devfn];
-            if (d)
-                pci_bios_init_device(d);
-        }
-    }
+                fn(d);
+        }
+    }
+}
+
+void pci_info(void)
+{
+    pci_for_each_device(pci_info_device);
 }
 
 /* Initialize a PCI NIC.  */
@@ -1864,6 +493,8 @@ void pci_nic_init(PCIBus *bus, NICInfo *
         pci_ne2000_init(bus, nd);
     } else if (strcmp(nd->model, "rtl8139") == 0) {
         pci_rtl8139_init(bus, nd);
+    } else if (strcmp(nd->model, "pcnet") == 0) {
+        pci_pcnet_init(bus, nd);
     } else {
         fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model);
         exit (1);
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/pcspk.c
--- a/tools/ioemu/hw/pcspk.c    Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/hw/pcspk.c    Mon Aug 07 18:25:30 2006 +0100
@@ -95,7 +95,7 @@ int pcspk_audio_init(AudioState *audio)
 int pcspk_audio_init(AudioState *audio)
 {
     PCSpkState *s = &pcspk_state;
-    audsettings_t as = {PCSPK_SAMPLE_RATE, 1, AUD_FMT_U8};
+    audsettings_t as = {PCSPK_SAMPLE_RATE, 1, AUD_FMT_U8, 0};
 
     if (!audio) {
         AUD_log(s_spk, "No audio state\n");
@@ -103,7 +103,7 @@ int pcspk_audio_init(AudioState *audio)
     }
     AUD_register_card(audio, s_spk, &s->card);
 
-    s->voice = AUD_open_out(&s->card, s->voice, s_spk, s, pcspk_callback, &as, 
0);
+    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;
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/piix4acpi.c
--- a/tools/ioemu/hw/piix4acpi.c        Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/hw/piix4acpi.c        Mon Aug 07 18:25:30 2006 +0100
@@ -375,7 +375,7 @@ static void acpi_map(PCIDevice *pci_dev,
 }
 
 /* PIIX4 acpi pci configuration space, func 3 */
-void pci_piix4_acpi_init(PCIBus *bus)
+void pci_piix4_acpi_init(PCIBus *bus, int devfn)
 {
     PCIAcpiState *d;
     uint8_t *pci_conf;
@@ -383,7 +383,7 @@ void pci_piix4_acpi_init(PCIBus *bus)
     /* register a function 3 of PIIX4 */
     d = (PCIAcpiState *)pci_register_device(
         bus, "PIIX4 ACPI", sizeof(PCIAcpiState),
-        ((PCIDevice *)piix3_state)->devfn + 3, NULL, NULL);
+        devfn, NULL, NULL);
 
     acpi_state = d;
     pci_conf = d->dev.config;
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/pl050.c
--- a/tools/ioemu/hw/pl050.c    Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/hw/pl050.c    Mon Aug 07 18:25:30 2006 +0100
@@ -1,5 +1,5 @@
 /* 
- * Arm PrimeCell PL050 Kyeboard / Mouse Interface
+ * Arm PrimeCell PL050 Keyboard / Mouse Interface
  *
  * Copyright (c) 2006 CodeSourcery.
  * Written by Paul Brook
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/ppc_chrp.c
--- a/tools/ioemu/hw/ppc_chrp.c Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/hw/ppc_chrp.c Mon Aug 07 18:25:30 2006 +0100
@@ -415,19 +415,18 @@ static void ppc_chrp_init(int ram_size, 
 
     if (is_heathrow) {
         isa_mem_base = 0x80000000;
-        pci_bus = pci_grackle_init(0xfec00000);
         
         /* Register 2 MB of ISA IO space */
         PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, 
NULL);
         cpu_register_physical_memory(0xfe000000, 0x00200000, PPC_io_memory);
         
         /* init basic PC hardware */
+        pic = heathrow_pic_init(&heathrow_pic_mem_index);
+        set_irq = heathrow_pic_set_irq;
+        pci_bus = pci_grackle_init(0xfec00000, pic);
         vga_initialize(pci_bus, ds, phys_ram_base + ram_size, 
                        ram_size, vga_ram_size,
                        vga_bios_offset, vga_bios_size);
-        pic = heathrow_pic_init(&heathrow_pic_mem_index);
-        set_irq = heathrow_pic_set_irq;
-        pci_set_pic(pci_bus, set_irq, pic);
 
         /* XXX: suppress that */
         isa_pic = pic_init(pic_irq_request, NULL);
@@ -462,7 +461,6 @@ static void ppc_chrp_init(int ram_size, 
         arch_name = "HEATHROW";
     } else {
         isa_mem_base = 0x80000000;
-        pci_bus = pci_pmac_init();
         
         /* Register 8 MB of ISA IO space */
         PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, 
NULL);
@@ -472,13 +470,13 @@ static void ppc_chrp_init(int ram_size, 
         unin_memory = cpu_register_io_memory(0, unin_read, unin_write, NULL);
         cpu_register_physical_memory(0xf8000000, 0x00001000, unin_memory);
 
+        pic = openpic_init(NULL, &openpic_mem_index, 1, &env);
+        set_irq = openpic_set_irq;
+        pci_bus = pci_pmac_init(pic);
         /* init basic PC hardware */
         vga_initialize(pci_bus, ds, phys_ram_base + ram_size,
                        ram_size, vga_ram_size,
                        vga_bios_offset, vga_bios_size);
-        pic = openpic_init(NULL, &openpic_mem_index, 1, &env);
-        set_irq = openpic_set_irq;
-        pci_set_pic(pci_bus, set_irq, pic);
 
         /* XXX: suppress that */
         isa_pic = pic_init(pic_irq_request, NULL);
@@ -508,7 +506,11 @@ static void ppc_chrp_init(int ram_size, 
         
         arch_name = "MAC99";
     }
-    
+
+    if (usb_enabled) {
+        usb_ohci_init(pci_bus, 3, -1);
+    }
+
     if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8)
         graphic_depth = 15;
 
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/ppc_prep.c
--- a/tools/ioemu/hw/ppc_prep.c Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/hw/ppc_prep.c Mon Aug 07 18:25:30 2006 +0100
@@ -665,6 +665,10 @@ static void ppc_prep_init(int ram_size, 
     cpu_register_physical_memory(0xFEFF0000, 0x1000, PPC_io_memory);
 #endif
 
+    if (usb_enabled) {
+        usb_ohci_init(pci_bus, 3, -1);
+    }
+
     nvram = m48t59_init(8, 0, 0x0074, NVRAM_SIZE, 59);
     if (nvram == NULL)
         return;
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/rtl8139.c
--- a/tools/ioemu/hw/rtl8139.c  Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/hw/rtl8139.c  Mon Aug 07 18:25:30 2006 +0100
@@ -23,14 +23,32 @@
  
  * 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
  */
 
 #include "vl.h"
-
 
 /* debug RTL8139 card */
 //#define DEBUG_RTL8139 1
+
+#define PCI_FREQUENCY 33000000L
 
 /* debug RTL8139 card C+ mode only */
 //#define DEBUG_RTL8139CP 1
@@ -39,6 +57,8 @@
    ignored by most drivers, disabled by default */
 //#define RTL8139_CALCULATE_RXCRC 1
 
+/* Uncomment to enable on-board timer interrupts */
+//#define RTL8139_ONBOARD_TIMER 1
 
 #if defined(RTL8139_CALCULATE_RXCRC)
 /* For crc32 */
@@ -52,12 +72,19 @@
 #define MOD2(input, size) \
     ( ( input ) & ( size - 1 )  )
 
+#if defined (DEBUG_RTL8139)
+#  define DEBUG_PRINT(x) do { printf x ; } while (0)
+#else
+#  define DEBUG_PRINT(x)
+#endif
+
 /* Symbolic offsets to registers. */
 enum RTL8139_registers {
     MAC0 = 0,        /* Ethernet hardware address. */
     MAR0 = 8,        /* Multicast filter. */
-    TxStatus0 = 0x10,    /* Transmit status (Four 32bit registers). */
-    TxAddr0 = 0x20,        /* Tx descriptors (also four 32bit). */
+    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,
@@ -115,8 +142,10 @@ enum ChipCmdBits {
 
 /* C+ mode */
 enum CplusCmdBits {
-    CPlusRxEnb = 0x0002,
-    CPlusTxEnb = 0x0001,
+    CPlusRxVLAN   = 0x0040, /* enable receive VLAN detagging */
+    CPlusRxChkSum = 0x0020, /* enable receive checksum offloading */
+    CPlusRxEnb    = 0x0002,
+    CPlusTxEnb    = 0x0001,
 };
 
 /* Interrupt register bits, using my own meaningful names. */
@@ -315,6 +344,11 @@ enum chip_flags {
     (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)
@@ -356,11 +390,41 @@ typedef struct EEprom9346
     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);
+
+/* Writes tally counters to specified physical memory address */
+static void RTL8139TallyCounters_physical_memory_write(target_phys_addr_t 
tc_addr, RTL8139TallyCounters* counters);
+
+/* Loads values of tally counters from VM state file */
+static void RTL8139TallyCounters_load(QEMUFile* f, RTL8139TallyCounters 
*tally_counters);
+
+/* Saves values of tally counters to VM state file */
+static void RTL8139TallyCounters_save(QEMUFile* f, RTL8139TallyCounters 
*tally_counters);
+
 typedef struct RTL8139State {
     uint8_t phys[8]; /* mac address */
     uint8_t mult[8]; /* multicast mask array */
 
-    uint32_t TxStatus[4]; /* TxStatus0 */
+    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 */
@@ -414,14 +478,27 @@ typedef struct RTL8139State {
     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;
+
 } RTL8139State;
 
 void prom9346_decode_command(EEprom9346 *eeprom, uint8_t command)
 {
-#if defined(DEBUG_RTL8139)
-    printf("RTL8139: eeprom command 0x%02x\n", command);
-#endif
+    DEBUG_PRINT(("RTL8139: eeprom command 0x%02x\n", command));
 
     switch (command & Chip9346_op_mask)
     {
@@ -432,10 +509,8 @@ void prom9346_decode_command(EEprom9346 
             eeprom->eedo = 0;
             eeprom->tick = 0;
             eeprom->mode = Chip9346_data_read;
-#if defined(DEBUG_RTL8139)
-            printf("RTL8139: eeprom read from address 0x%02x data=0x%04x\n",
-                   eeprom->address, eeprom->output);
-#endif
+            DEBUG_PRINT(("RTL8139: eeprom read from address 0x%02x 
data=0x%04x\n",
+                   eeprom->address, eeprom->output));
         }
         break;
 
@@ -445,10 +520,8 @@ void prom9346_decode_command(EEprom9346 
             eeprom->input = 0;
             eeprom->tick = 0;
             eeprom->mode = Chip9346_none; /* Chip9346_data_write */
-#if defined(DEBUG_RTL8139)
-            printf("RTL8139: eeprom begin write to address 0x%02x\n",
-                   eeprom->address);
-#endif
+            DEBUG_PRINT(("RTL8139: eeprom begin write to address 0x%02x\n",
+                   eeprom->address));
         }
         break;
         default:
@@ -456,19 +529,13 @@ void prom9346_decode_command(EEprom9346 
             switch (command & Chip9346_op_ext_mask)
             {
                 case Chip9346_op_write_enable:
-#if defined(DEBUG_RTL8139)
-                    printf("RTL8139: eeprom write enabled\n");
-#endif
+                    DEBUG_PRINT(("RTL8139: eeprom write enabled\n"));
                     break;
                 case Chip9346_op_write_all:
-#if defined(DEBUG_RTL8139)
-                    printf("RTL8139: eeprom begin write all\n");
-#endif
+                    DEBUG_PRINT(("RTL8139: eeprom begin write all\n"));
                     break;
                 case Chip9346_op_write_disable:
-#if defined(DEBUG_RTL8139)
-                    printf("RTL8139: eeprom write disabled\n");
-#endif
+                    DEBUG_PRINT(("RTL8139: eeprom write disabled\n"));
                     break;
             }
             break;
@@ -481,9 +548,7 @@ void prom9346_shift_clock(EEprom9346 *ee
 
     ++ eeprom->tick;
 
-#if defined(DEBUG_RTL8139)
-    printf("eeprom: tick %d eedi=%d eedo=%d\n", eeprom->tick, eeprom->eedi, 
eeprom->eedo);
-#endif
+    DEBUG_PRINT(("eeprom: tick %d eedi=%d eedo=%d\n", eeprom->tick, 
eeprom->eedi, eeprom->eedo));
 
     switch (eeprom->mode)
     {
@@ -493,9 +558,7 @@ void prom9346_shift_clock(EEprom9346 *ee
                 eeprom->mode = Chip9346_read_command;
                 eeprom->tick = 0;
                 eeprom->input = 0;
-#if defined(DEBUG_RTL8139)
-                printf("eeprom: +++ synchronized, begin command read\n");
-#endif
+                DEBUG_PRINT(("eeprom: +++ synchronized, begin command 
read\n"));
             }
             break;
 
@@ -512,14 +575,24 @@ void prom9346_shift_clock(EEprom9346 *ee
             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;
+
+                DEBUG_PRINT(("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;
 
-#if defined(DEBUG_RTL8139)
-                printf("eeprom: +++ read next address 0x%02x data=0x%04x\n",
-                       eeprom->address, eeprom->output);
+                DEBUG_PRINT(("eeprom: +++ read next address 0x%02x 
data=0x%04x\n",
+                       eeprom->address, eeprom->output));
 #endif
             }
             break;
@@ -528,10 +601,9 @@ void prom9346_shift_clock(EEprom9346 *ee
             eeprom->input = (eeprom->input << 1) | (bit & 1);
             if (eeprom->tick == 16)
             {
-#if defined(DEBUG_RTL8139)
-            printf("RTL8139: eeprom write to address 0x%02x data=0x%04x\n",
-                   eeprom->address, eeprom->input);
-#endif
+                DEBUG_PRINT(("RTL8139: 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;
@@ -548,10 +620,9 @@ void prom9346_shift_clock(EEprom9346 *ee
                 {
                     eeprom->contents[i] = eeprom->input;
                 }
-#if defined(DEBUG_RTL8139)
-                printf("RTL8139: eeprom filled with data=0x%04x\n",
-                       eeprom->input);
-#endif
+                DEBUG_PRINT(("RTL8139: eeprom filled with data=0x%04x\n",
+                       eeprom->input));
+
                 eeprom->mode = Chip9346_enter_command_mode;
                 eeprom->tick = 0;
                 eeprom->input = 0;
@@ -582,9 +653,8 @@ void prom9346_set_wire(RTL8139State *s, 
     eeprom->eesk = eesk;
     eeprom->eedi = eedi;
 
-#if defined(DEBUG_RTL8139)
-    printf("eeprom: +++ wires CS=%d SK=%d DI=%d DO=%d\n", eeprom->eecs, 
eeprom->eesk, eeprom->eedi, eeprom->eedo);
-#endif
+    DEBUG_PRINT(("eeprom: +++ wires CS=%d SK=%d DI=%d DO=%d\n",
+                 eeprom->eecs, eeprom->eesk, eeprom->eedi, eeprom->eedo));
 
     if (!old_eecs && eecs)
     {
@@ -594,17 +664,12 @@ void prom9346_set_wire(RTL8139State *s, 
         eeprom->output = 0;
         eeprom->mode = Chip9346_enter_command_mode;
 
-#if defined(DEBUG_RTL8139)
-        printf("=== eeprom: begin access, enter command mode\n");
-#endif
-
+        DEBUG_PRINT(("=== eeprom: begin access, enter command mode\n"));
     }
 
     if (!eecs)
     {
-#if defined(DEBUG_RTL8139)
-        printf("=== eeprom: end access\n");
-#endif
+        DEBUG_PRINT(("=== eeprom: end access\n"));
         return;
     }
 
@@ -619,10 +684,10 @@ static void rtl8139_update_irq(RTL8139St
 {
     int isr;
     isr = (s->IntrStatus & s->IntrMask) & 0xffff;
-#if defined(DEBUG_RTL8139)
-    printf("RTL8139: Set IRQ line %d to %d (%04x %04x)\n",
-       s->irq, isr ? 1 : 0, s->IntrStatus, s->IntrMask);
-#endif
+
+    DEBUG_PRINT(("RTL8139: Set IRQ line %d to %d (%04x %04x)\n",
+       s->irq, isr ? 1 : 0, s->IntrStatus, s->IntrMask));
+
     if (s->irq == 16) {
         /* PCI irq */
         pci_set_irq(s->pci_dev, 0, (isr != 0));
@@ -691,9 +756,7 @@ static void rtl8139_write_buffer(RTL8139
         /* write packet data */
         if (wrapped && s->RxBufferSize < 65536 && !rtl8139_RxWrap(s))
         {
-    #if defined(DEBUG_RTL8139)
-            printf(">>> RTL8139: rx packet wrapped in buffer at %d\n", 
size-wrapped);
-    #endif
+            DEBUG_PRINT((">>> RTL8139: rx packet wrapped in buffer at %d\n", 
size-wrapped));
 
             if (size > wrapped)
             {
@@ -751,7 +814,7 @@ static int rtl8139_can_receive(void *opa
     }
 }
 
-static void rtl8139_receive(void *opaque, const uint8_t *buf, int size)
+static void rtl8139_do_receive(void *opaque, const uint8_t *buf, int size, int 
do_interrupt)
 {
     RTL8139State *s = opaque;
 
@@ -761,16 +824,12 @@ static void rtl8139_receive(void *opaque
     static const uint8_t broadcast_macaddr[6] = 
         { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 
-#if defined(DEBUG_RTL8139)
-    printf(">>> RTL8139: received len=%d\n", size);
-#endif
+    DEBUG_PRINT((">>> RTL8139: received len=%d\n", size));
 
     /* test if board clock is stopped */
     if (!s->clock_enabled)
     {
-#if defined(DEBUG_RTL8139)
-        printf("RTL8139: stopped ==========================\n");
-#endif
+        DEBUG_PRINT(("RTL8139: stopped ==========================\n"));
         return;
     }
 
@@ -778,42 +837,44 @@ static void rtl8139_receive(void *opaque
 
     if (!rtl8139_receiver_enabled(s))
     {
-#if defined(DEBUG_RTL8139)
-        printf("RTL8139: receiver disabled ================\n");
-#endif
+        DEBUG_PRINT(("RTL8139: receiver disabled ================\n"));
         return;
     }
 
     /* XXX: check this */
     if (s->RxConfig & AcceptAllPhys) {
         /* promiscuous: receive all */
-#if defined(DEBUG_RTL8139)
-        printf(">>> RTL8139: packet received in promiscuous mode\n");
-#endif
+        DEBUG_PRINT((">>> RTL8139: packet received in promiscuous mode\n"));
 
     } else {
         if (!memcmp(buf,  broadcast_macaddr, 6)) {
             /* broadcast address */
             if (!(s->RxConfig & AcceptBroadcast))
             {
-#if defined(DEBUG_RTL8139)
-                printf(">>> RTL8139: broadcast packet rejected\n");
-#endif
+                DEBUG_PRINT((">>> RTL8139: broadcast packet rejected\n"));
+
+                /* update tally counter */
+                ++s->tally_counters.RxERR;
+
                 return;
             }
 
             packet_header |= RxBroadcast;
 
-#if defined(DEBUG_RTL8139)
-            printf(">>> RTL8139: broadcast packet received\n");
-#endif
+            DEBUG_PRINT((">>> RTL8139: broadcast packet received\n"));
+
+            /* update tally counter */
+            ++s->tally_counters.RxOkBrd;
+
         } else if (buf[0] & 0x01) {
             /* multicast */
             if (!(s->RxConfig & AcceptMulticast))
             {
-#if defined(DEBUG_RTL8139)
-                printf(">>> RTL8139: multicast packet rejected\n");
-#endif
+                DEBUG_PRINT((">>> RTL8139: multicast packet rejected\n"));
+
+                /* update tally counter */
+                ++s->tally_counters.RxERR;
+
                 return;
             }
 
@@ -821,17 +882,21 @@ static void rtl8139_receive(void *opaque
 
             if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))))
             {
-#if defined(DEBUG_RTL8139)
-                printf(">>> RTL8139: multicast address mismatch\n");
-#endif
+                DEBUG_PRINT((">>> RTL8139: multicast address mismatch\n"));
+
+                /* update tally counter */
+                ++s->tally_counters.RxERR;
+
                 return;
             }
 
             packet_header |= RxMulticast;
 
-#if defined(DEBUG_RTL8139)
-            printf(">>> RTL8139: multicast packet received\n");
-#endif
+            DEBUG_PRINT((">>> RTL8139: 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] &&            
@@ -841,23 +906,28 @@ static void rtl8139_receive(void *opaque
             /* match */
             if (!(s->RxConfig & AcceptMyPhys))
             {
-#if defined(DEBUG_RTL8139)
-                printf(">>> RTL8139: rejecting physical address matching 
packet\n");
-#endif
+                DEBUG_PRINT((">>> RTL8139: rejecting physical address matching 
packet\n"));
+
+                /* update tally counter */
+                ++s->tally_counters.RxERR;
+
                 return;
             }
 
             packet_header |= RxPhysical;
 
-#if defined(DEBUG_RTL8139)
-            printf(">>> RTL8139: physical address matching packet received\n");
-#endif
+            DEBUG_PRINT((">>> RTL8139: physical address matching packet 
received\n"));
+
+            /* update tally counter */
+            ++s->tally_counters.RxOkPhy;
 
         } else {
 
-#if defined(DEBUG_RTL8139)
-                printf(">>> RTL8139: unknown packet\n");
-#endif
+            DEBUG_PRINT((">>> RTL8139: unknown packet\n"));
+
+            /* update tally counter */
+            ++s->tally_counters.RxERR;
+
             return;
         }
     }
@@ -872,9 +942,7 @@ static void rtl8139_receive(void *opaque
 
     if (rtl8139_cp_receiver_enabled(s))
     {
-#if defined(DEBUG_RTL8139)
-        printf("RTL8139: in C+ Rx mode ================\n");
-#endif
+        DEBUG_PRINT(("RTL8139: in C+ Rx mode ================\n"));
 
         /* begin C+ receiver mode */
 
@@ -897,10 +965,8 @@ static void rtl8139_receive(void *opaque
         cplus_rx_ring_desc = rtl8139_addr64(s->RxRingAddrLO, s->RxRingAddrHI);
         cplus_rx_ring_desc += 16 * descriptor;
 
-#ifdef DEBUG_RTL8139
-        printf("RTL8139: +++ C+ mode reading RX descriptor %d from host memory 
at %08x %08x = 0x%8lx\n",
-               descriptor, s->RxRingAddrHI, s->RxRingAddrLO, 
cplus_rx_ring_desc);
-#endif
+        DEBUG_PRINT(("RTL8139: +++ C+ mode reading RX descriptor %d from host 
memory at %08x %08x = %016" PRIx64 "\n",
+               descriptor, s->RxRingAddrHI, s->RxRingAddrLO, 
(uint64_t)cplus_rx_ring_desc));
 
         uint32_t val, rxdw0,rxdw1,rxbufLO,rxbufHI;
 
@@ -913,33 +979,41 @@ static void rtl8139_receive(void *opaque
         cpu_physical_memory_read(cplus_rx_ring_desc+12, (uint8_t *)&val, 4);
         rxbufHI = le32_to_cpu(val);
 
-#ifdef DEBUG_RTL8139
-        printf("RTL8139: +++ C+ mode RX descriptor %d %08x %08x %08x %08x\n",
+        DEBUG_PRINT(("RTL8139: +++ C+ mode RX descriptor %d %08x %08x %08x 
%08x\n",
                descriptor,
-               rxdw0, rxdw1, rxbufLO, rxbufHI);
-#endif
+               rxdw0, rxdw1, rxbufLO, rxbufHI));
 
         if (!(rxdw0 & CP_RX_OWN))
         {
-#if defined(DEBUG_RTL8139)
-            printf("RTL8139: C+ Rx mode : descriptor %d is owned by host\n", 
descriptor);
-#endif
+            DEBUG_PRINT(("RTL8139: 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;
         }
 
         uint32_t rx_space = rxdw0 & CP_RX_BUFFER_SIZE_MASK;
 
+        /* TODO: scatter the packet over available receive ring descriptors 
space */
+
         if (size+4 > rx_space)
         {
-#if defined(DEBUG_RTL8139)
-            printf("RTL8139: C+ Rx mode : descriptor %d size %d received %d + 
4\n",
-                   descriptor, rx_space, size);
-#endif
+            DEBUG_PRINT(("RTL8139: 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;
         }
@@ -948,6 +1022,11 @@ static void rtl8139_receive(void *opaque
 
         /* receive/copy to target memory */
         cpu_physical_memory_write( rx_addr, buf, size );
+
+        if (s->CpCmd & CPlusRxChkSum)
+        {
+            /* do some packet checksumming */
+        }
 
         /* write checksum */
 #if defined (RTL8139_CALCULATE_RXCRC)
@@ -1008,6 +1087,9 @@ static void rtl8139_receive(void *opaque
         val = cpu_to_le32(rxdw1);
         cpu_physical_memory_write(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)
         {
@@ -1018,16 +1100,13 @@ static void rtl8139_receive(void *opaque
             ++s->currCPlusRxDesc;
         }
 
-#if defined(DEBUG_RTL8139)
-        printf("RTL8139: done C+ Rx mode ----------------\n");
-#endif
+        DEBUG_PRINT(("RTL8139: done C+ Rx mode ----------------\n"));
 
     }
     else
     {
-#if defined(DEBUG_RTL8139)
-        printf("RTL8139: in ring Rx mode ================\n");
-#endif
+        DEBUG_PRINT(("RTL8139: in ring Rx mode ================\n"));
+
         /* begin ring receiver mode */
         int avail = MOD2(s->RxBufferSize + s->RxBufPtr - s->RxBufAddr, 
s->RxBufferSize);
 
@@ -1035,10 +1114,9 @@ static void rtl8139_receive(void *opaque
 
         if (avail != 0 && size + 8 >= avail)
         {
-#if defined(DEBUG_RTL8139)
-            printf("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);
-#endif
+            DEBUG_PRINT(("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);
@@ -1070,15 +1148,21 @@ static void rtl8139_receive(void *opaque
 
         /* now we can signal we have received something */
 
-#if defined(DEBUG_RTL8139)
-        printf("   received: rx buffer length %d head 0x%04x read 0x%04x\n",
-               s->RxBufferSize, s->RxBufAddr, s->RxBufPtr);
-#endif
-
+        DEBUG_PRINT(("   received: rx buffer length %d head 0x%04x read 
0x%04x\n",
+               s->RxBufferSize, s->RxBufAddr, s->RxBufPtr));
     }
 
     s->IntrStatus |= RxOK;
-    rtl8139_update_irq(s);
+
+    if (do_interrupt)
+    {
+        rtl8139_update_irq(s);
+    }
+}
+
+static void rtl8139_receive(void *opaque, const uint8_t *buf, int size)
+{
+    rtl8139_do_receive(opaque, buf, size, 1);
 }
 
 static void rtl8139_reset_rxring(RTL8139State *s, uint32_t bufferSize)
@@ -1103,6 +1187,11 @@ static void rtl8139_reset(RTL8139State *
 
     /* prepare eeprom */
     s->eeprom.contents[0] = 0x8129;
+#if 1
+    // PCI vendor and device ID should be mirrored here
+    s->eeprom.contents[1] = 0x10ec;
+    s->eeprom.contents[2] = 0x8139;
+#endif
     memcpy(&s->eeprom.contents[7], s->macaddr, 6);
 
     /* mark all status registers as owned by host */
@@ -1129,7 +1218,7 @@ static void rtl8139_reset(RTL8139State *
 //    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, 0, 0); // RTL-8139C HasLWake
+    s->TxConfig |= HW_REVID(1, 1, 1, 0, 1, 1, 0); // RTL-8139C+ HasLWake
     s->clock_enabled = 1;
 #endif
 
@@ -1157,34 +1246,137 @@ static void rtl8139_reset(RTL8139State *
     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);
+}
+
+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_physical_memory_write(target_phys_addr_t 
tc_addr, RTL8139TallyCounters* tally_counters)
+{
+    uint16_t val16;
+    uint32_t val32;
+    uint64_t val64;
+
+    val64 = cpu_to_le64(tally_counters->TxOk);
+    cpu_physical_memory_write(tc_addr + 0,    (uint8_t *)&val64, 8);
+
+    val64 = cpu_to_le64(tally_counters->RxOk);
+    cpu_physical_memory_write(tc_addr + 8,    (uint8_t *)&val64, 8);
+
+    val64 = cpu_to_le64(tally_counters->TxERR);
+    cpu_physical_memory_write(tc_addr + 16,    (uint8_t *)&val64, 8);
+
+    val32 = cpu_to_le32(tally_counters->RxERR);
+    cpu_physical_memory_write(tc_addr + 24,    (uint8_t *)&val32, 4);
+
+    val16 = cpu_to_le16(tally_counters->MissPkt);
+    cpu_physical_memory_write(tc_addr + 28,    (uint8_t *)&val16, 2);
+
+    val16 = cpu_to_le16(tally_counters->FAE);
+    cpu_physical_memory_write(tc_addr + 30,    (uint8_t *)&val16, 2);
+
+    val32 = cpu_to_le32(tally_counters->Tx1Col);
+    cpu_physical_memory_write(tc_addr + 32,    (uint8_t *)&val32, 4);
+
+    val32 = cpu_to_le32(tally_counters->TxMCol);
+    cpu_physical_memory_write(tc_addr + 36,    (uint8_t *)&val32, 4);
+
+    val64 = cpu_to_le64(tally_counters->RxOkPhy);
+    cpu_physical_memory_write(tc_addr + 40,    (uint8_t *)&val64, 8);
+
+    val64 = cpu_to_le64(tally_counters->RxOkBrd);
+    cpu_physical_memory_write(tc_addr + 48,    (uint8_t *)&val64, 8);
+
+    val32 = cpu_to_le32(tally_counters->RxOkMul);
+    cpu_physical_memory_write(tc_addr + 56,    (uint8_t *)&val32, 4);
+
+    val16 = cpu_to_le16(tally_counters->TxAbt);
+    cpu_physical_memory_write(tc_addr + 60,    (uint8_t *)&val16, 2);
+
+    val16 = cpu_to_le16(tally_counters->TxUndrn);
+    cpu_physical_memory_write(tc_addr + 62,    (uint8_t *)&val16, 2);
+}
+
+/* Loads values of tally counters from VM state file */
+static void RTL8139TallyCounters_load(QEMUFile* f, RTL8139TallyCounters 
*tally_counters)
+{
+    qemu_get_be64s(f, &tally_counters->TxOk);
+    qemu_get_be64s(f, &tally_counters->RxOk);
+    qemu_get_be64s(f, &tally_counters->TxERR);
+    qemu_get_be32s(f, &tally_counters->RxERR);
+    qemu_get_be16s(f, &tally_counters->MissPkt);
+    qemu_get_be16s(f, &tally_counters->FAE);
+    qemu_get_be32s(f, &tally_counters->Tx1Col);
+    qemu_get_be32s(f, &tally_counters->TxMCol);
+    qemu_get_be64s(f, &tally_counters->RxOkPhy);
+    qemu_get_be64s(f, &tally_counters->RxOkBrd);
+    qemu_get_be32s(f, &tally_counters->RxOkMul);
+    qemu_get_be16s(f, &tally_counters->TxAbt);
+    qemu_get_be16s(f, &tally_counters->TxUndrn);
+}
+
+/* Saves values of tally counters to VM state file */
+static void RTL8139TallyCounters_save(QEMUFile* f, RTL8139TallyCounters 
*tally_counters)
+{
+    qemu_put_be64s(f, &tally_counters->TxOk);
+    qemu_put_be64s(f, &tally_counters->RxOk);
+    qemu_put_be64s(f, &tally_counters->TxERR);
+    qemu_put_be32s(f, &tally_counters->RxERR);
+    qemu_put_be16s(f, &tally_counters->MissPkt);
+    qemu_put_be16s(f, &tally_counters->FAE);
+    qemu_put_be32s(f, &tally_counters->Tx1Col);
+    qemu_put_be32s(f, &tally_counters->TxMCol);
+    qemu_put_be64s(f, &tally_counters->RxOkPhy);
+    qemu_put_be64s(f, &tally_counters->RxOkBrd);
+    qemu_put_be32s(f, &tally_counters->RxOkMul);
+    qemu_put_be16s(f, &tally_counters->TxAbt);
+    qemu_put_be16s(f, &tally_counters->TxUndrn);
 }
 
 static void rtl8139_ChipCmd_write(RTL8139State *s, uint32_t val)
 {
     val &= 0xff;
 
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: ChipCmd write val=0x%08x\n", val);
-#endif
+    DEBUG_PRINT(("RTL8139: ChipCmd write val=0x%08x\n", val));
 
     if (val & CmdReset)
     {
-#ifdef DEBUG_RTL8139
-        printf("RTL8139: ChipCmd reset\n");
-#endif
+        DEBUG_PRINT(("RTL8139: ChipCmd reset\n"));
         rtl8139_reset(s);
     }
     if (val & CmdRxEnb)
     {
-#ifdef DEBUG_RTL8139
-        printf("RTL8139: ChipCmd enable receiver\n");
-#endif
+        DEBUG_PRINT(("RTL8139: ChipCmd enable receiver\n"));
+
+        s->currCPlusRxDesc = 0;
     }
     if (val & CmdTxEnb)
     {
-#ifdef DEBUG_RTL8139
-        printf("RTL8139: ChipCmd enable transmitter\n");
-#endif
+        DEBUG_PRINT(("RTL8139: ChipCmd enable transmitter\n"));
+
+        s->currCPlusTxDesc = 0;
     }
 
     /* mask unwriteable bits */
@@ -1202,15 +1394,11 @@ static int rtl8139_RxBufferEmpty(RTL8139
 
     if (unread != 0)
     {
-#ifdef DEBUG_RTL8139
-        printf("RTL8139: receiver buffer data available 0x%04x\n", unread);
-#endif
+        DEBUG_PRINT(("RTL8139: receiver buffer data available 0x%04x\n", 
unread));
         return 0;
     }
 
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: receiver buffer is empty\n");
-#endif
+    DEBUG_PRINT(("RTL8139: receiver buffer is empty\n"));
 
     return 1;
 }
@@ -1222,9 +1410,7 @@ static uint32_t rtl8139_ChipCmd_read(RTL
     if (rtl8139_RxBufferEmpty(s))
         ret |= RxBufEmpty;
 
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: ChipCmd read val=0x%04x\n", ret);
-#endif
+    DEBUG_PRINT(("RTL8139: ChipCmd read val=0x%04x\n", ret));
 
     return ret;
 }
@@ -1233,9 +1419,7 @@ static void rtl8139_CpCmd_write(RTL8139S
 {
     val &= 0xffff;
 
-#ifdef DEBUG_RTL8139
-    printf("RTL8139C+ command register write(w) val=0x%04x\n", val);
-#endif
+    DEBUG_PRINT(("RTL8139C+ command register write(w) val=0x%04x\n", val));
 
     /* mask unwriteable bits */
     val = SET_MASKED(val, 0xff84, s->CpCmd);
@@ -1247,13 +1431,25 @@ static uint32_t rtl8139_CpCmd_read(RTL81
 {
     uint32_t ret = s->CpCmd;
 
-#ifdef DEBUG_RTL8139
-    printf("RTL8139C+ command register read(w) val=0x%04x\n", ret);
-#endif
+    DEBUG_PRINT(("RTL8139C+ command register read(w) val=0x%04x\n", ret));
 
     return ret;
 }
 
+static void rtl8139_IntrMitigate_write(RTL8139State *s, uint32_t val)
+{
+    DEBUG_PRINT(("RTL8139C+ IntrMitigate register write(w) val=0x%04x\n", 
val));
+}
+
+static uint32_t rtl8139_IntrMitigate_read(RTL8139State *s)
+{
+    uint32_t ret = 0;
+
+    DEBUG_PRINT(("RTL8139C+ IntrMitigate register read(w) val=0x%04x\n", ret));
+
+    return ret;
+}
+
 int rtl8139_config_writeable(RTL8139State *s)
 {
     if (s->Cfg9346 & Cfg9346_Unlock)
@@ -1261,9 +1457,7 @@ int rtl8139_config_writeable(RTL8139Stat
         return 1;
     }
 
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: Configuration registers are write-protected\n");
-#endif
+    DEBUG_PRINT(("RTL8139: Configuration registers are write-protected\n"));
 
     return 0;
 }
@@ -1272,9 +1466,7 @@ static void rtl8139_BasicModeCtrl_write(
 {
     val &= 0xffff;
 
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: BasicModeCtrl register write(w) val=0x%04x\n", val);
-#endif
+    DEBUG_PRINT(("RTL8139: BasicModeCtrl register write(w) val=0x%04x\n", 
val));
 
     /* mask unwriteable bits */
     uint32 mask = 0x4cff;
@@ -1296,9 +1488,7 @@ static uint32_t rtl8139_BasicModeCtrl_re
 {
     uint32_t ret = s->BasicModeCtrl;
 
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: BasicModeCtrl register read(w) val=0x%04x\n", ret);
-#endif
+    DEBUG_PRINT(("RTL8139: BasicModeCtrl register read(w) val=0x%04x\n", ret));
 
     return ret;
 }
@@ -1307,9 +1497,7 @@ static void rtl8139_BasicModeStatus_writ
 {
     val &= 0xffff;
 
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: BasicModeStatus register write(w) val=0x%04x\n", val);
-#endif
+    DEBUG_PRINT(("RTL8139: BasicModeStatus register write(w) val=0x%04x\n", 
val));
 
     /* mask unwriteable bits */
     val = SET_MASKED(val, 0xff3f, s->BasicModeStatus);
@@ -1321,9 +1509,7 @@ static uint32_t rtl8139_BasicModeStatus_
 {
     uint32_t ret = s->BasicModeStatus;
 
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: BasicModeStatus register read(w) val=0x%04x\n", ret);
-#endif
+    DEBUG_PRINT(("RTL8139: BasicModeStatus register read(w) val=0x%04x\n", 
ret));
 
     return ret;
 }
@@ -1332,9 +1518,7 @@ static void rtl8139_Cfg9346_write(RTL813
 {
     val &= 0xff;
 
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: Cfg9346 write val=0x%02x\n", val);
-#endif
+    DEBUG_PRINT(("RTL8139: Cfg9346 write val=0x%02x\n", val));
 
     /* mask unwriteable bits */
     val = SET_MASKED(val, 0x31, s->Cfg9346);
@@ -1377,9 +1561,7 @@ static uint32_t rtl8139_Cfg9346_read(RTL
         }
     }
 
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: Cfg9346 read val=0x%02x\n", ret);
-#endif
+    DEBUG_PRINT(("RTL8139: Cfg9346 read val=0x%02x\n", ret));
 
     return ret;
 }
@@ -1388,9 +1570,7 @@ static void rtl8139_Config0_write(RTL813
 {
     val &= 0xff;
 
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: Config0 write val=0x%02x\n", val);
-#endif
+    DEBUG_PRINT(("RTL8139: Config0 write val=0x%02x\n", val));
 
     if (!rtl8139_config_writeable(s))
         return;
@@ -1405,9 +1585,7 @@ static uint32_t rtl8139_Config0_read(RTL
 {
     uint32_t ret = s->Config0;
 
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: Config0 read val=0x%02x\n", ret);
-#endif
+    DEBUG_PRINT(("RTL8139: Config0 read val=0x%02x\n", ret));
 
     return ret;
 }
@@ -1416,9 +1594,7 @@ static void rtl8139_Config1_write(RTL813
 {
     val &= 0xff;
 
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: Config1 write val=0x%02x\n", val);
-#endif
+    DEBUG_PRINT(("RTL8139: Config1 write val=0x%02x\n", val));
 
     if (!rtl8139_config_writeable(s))
         return;
@@ -1433,9 +1609,7 @@ static uint32_t rtl8139_Config1_read(RTL
 {
     uint32_t ret = s->Config1;
 
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: Config1 read val=0x%02x\n", ret);
-#endif
+    DEBUG_PRINT(("RTL8139: Config1 read val=0x%02x\n", ret));
 
     return ret;
 }
@@ -1444,9 +1618,7 @@ static void rtl8139_Config3_write(RTL813
 {
     val &= 0xff;
 
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: Config3 write val=0x%02x\n", val);
-#endif
+    DEBUG_PRINT(("RTL8139: Config3 write val=0x%02x\n", val));
 
     if (!rtl8139_config_writeable(s))
         return;
@@ -1461,9 +1633,7 @@ static uint32_t rtl8139_Config3_read(RTL
 {
     uint32_t ret = s->Config3;
 
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: Config3 read val=0x%02x\n", ret);
-#endif
+    DEBUG_PRINT(("RTL8139: Config3 read val=0x%02x\n", ret));
 
     return ret;
 }
@@ -1472,9 +1642,7 @@ static void rtl8139_Config4_write(RTL813
 {
     val &= 0xff;
 
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: Config4 write val=0x%02x\n", val);
-#endif
+    DEBUG_PRINT(("RTL8139: Config4 write val=0x%02x\n", val));
 
     if (!rtl8139_config_writeable(s))
         return;
@@ -1489,9 +1657,7 @@ static uint32_t rtl8139_Config4_read(RTL
 {
     uint32_t ret = s->Config4;
 
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: Config4 read val=0x%02x\n", ret);
-#endif
+    DEBUG_PRINT(("RTL8139: Config4 read val=0x%02x\n", ret));
 
     return ret;
 }
@@ -1500,9 +1666,7 @@ static void rtl8139_Config5_write(RTL813
 {
     val &= 0xff;
 
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: Config5 write val=0x%02x\n", val);
-#endif
+    DEBUG_PRINT(("RTL8139: Config5 write val=0x%02x\n", val));
 
     /* mask unwriteable bits */
     val = SET_MASKED(val, 0x80, s->Config5);
@@ -1514,9 +1678,7 @@ static uint32_t rtl8139_Config5_read(RTL
 {
     uint32_t ret = s->Config5;
 
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: Config5 read val=0x%02x\n", ret);
-#endif
+    DEBUG_PRINT(("RTL8139: Config5 read val=0x%02x\n", ret));
 
     return ret;
 }
@@ -1525,15 +1687,11 @@ static void rtl8139_TxConfig_write(RTL81
 {
     if (!rtl8139_transmitter_enabled(s))
     {
-#ifdef DEBUG_RTL8139
-        printf("RTL8139: transmitter disabled; no TxConfig write 
val=0x%08x\n", val);
-#endif
+        DEBUG_PRINT(("RTL8139: transmitter disabled; no TxConfig write 
val=0x%08x\n", val));
         return;
     }
 
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: TxConfig write val=0x%08x\n", val);
-#endif
+    DEBUG_PRINT(("RTL8139: TxConfig write val=0x%08x\n", val));
 
     val = SET_MASKED(val, TxVersionMask | 0x8070f80f, s->TxConfig);
 
@@ -1542,31 +1700,26 @@ static void rtl8139_TxConfig_write(RTL81
 
 static void rtl8139_TxConfig_writeb(RTL8139State *s, uint32_t val)
 {
-#ifdef DEBUG_RTL8139
-                printf("RTL8139C TxConfig via write(b) val=0x%02x\n", val);
-#endif
-            uint32_t tc = s->TxConfig;
-            tc &= 0xFFFFFF00;
-            tc |= (val & 0x000000FF);
-            rtl8139_TxConfig_write(s, tc);
+    DEBUG_PRINT(("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;
 
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: TxConfig read val=0x%04x\n", ret);
-#endif
+    DEBUG_PRINT(("RTL8139: TxConfig read val=0x%04x\n", ret));
 
     return ret;
 }
 
 static void rtl8139_RxConfig_write(RTL8139State *s, uint32_t val)
 {
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: RxConfig write val=0x%08x\n", val);
-#endif
+    DEBUG_PRINT(("RTL8139: RxConfig write val=0x%08x\n", val));
 
     /* mask unwriteable bits */
     val = SET_MASKED(val, 0xf0fc0040, s->RxConfig);
@@ -1576,61 +1729,70 @@ static void rtl8139_RxConfig_write(RTL81
     /* reset buffer size and read/write pointers */
     rtl8139_reset_rxring(s, 8192 << ((s->RxConfig >> 11) & 0x3));
 
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: RxConfig write reset buffer size to %d\n", 
s->RxBufferSize);
-#endif
+    DEBUG_PRINT(("RTL8139: RxConfig write reset buffer size to %d\n", 
s->RxBufferSize));
 }
 
 static uint32_t rtl8139_RxConfig_read(RTL8139State *s)
 {
     uint32_t ret = s->RxConfig;
 
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: RxConfig read val=0x%08x\n", ret);
-#endif
+    DEBUG_PRINT(("RTL8139: RxConfig read val=0x%08x\n", ret));
 
     return ret;
 }
 
+static void rtl8139_transfer_frame(RTL8139State *s, const uint8_t *buf, int 
size, int do_interrupt)
+{
+    if (!size)
+    {
+        DEBUG_PRINT(("RTL8139: +++ empty ethernet frame\n"));
+        return;
+    }
+
+    if (TxLoopBack == (s->TxConfig & TxLoopBack))
+    {
+        DEBUG_PRINT(("RTL8139: +++ transmit loopback mode\n"));
+        rtl8139_do_receive(s, buf, size, do_interrupt);
+    }
+    else
+    {
+        qemu_send_packet(s->vc, buf, size);
+    }
+}
+
 static int rtl8139_transmit_one(RTL8139State *s, int descriptor)
 {
     if (!rtl8139_transmitter_enabled(s))
     {
-#ifdef DEBUG_RTL8139
-        printf("RTL8139: +++ cannot transmit from descriptor %d: transmitter 
disabled\n", descriptor);
-#endif
+        DEBUG_PRINT(("RTL8139: +++ cannot transmit from descriptor %d: 
transmitter disabled\n",
+                     descriptor));
         return 0;
     }
 
     if (s->TxStatus[descriptor] & TxHostOwns)
     {
-#ifdef DEBUG_RTL8139
-        printf("RTL8139: +++ cannot transmit from descriptor %d: owned by host 
(%08x)\n", descriptor, s->TxStatus[descriptor]);
-#endif
+        DEBUG_PRINT(("RTL8139: +++ cannot transmit from descriptor %d: owned 
by host (%08x)\n",
+                     descriptor, s->TxStatus[descriptor]));
         return 0;
     }
 
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: +++ transmitting from descriptor %d\n", descriptor);
-#endif
+    DEBUG_PRINT(("RTL8139: +++ transmitting from descriptor %d\n", 
descriptor));
 
     int txsize = s->TxStatus[descriptor] & 0x1fff;
     uint8_t txbuffer[0x2000];
 
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: +++ transmit reading %d bytes from host memory at 
0x%08x\n", txsize, s->TxAddr[descriptor]);
-#endif
+    DEBUG_PRINT(("RTL8139: +++ transmit reading %d bytes from host memory at 
0x%08x\n",
+                 txsize, s->TxAddr[descriptor]));
+
     cpu_physical_memory_read(s->TxAddr[descriptor], txbuffer, txsize);
-
-    qemu_send_packet(s->vc, txbuffer, txsize);
 
     /* Mark descriptor as transferred */
     s->TxStatus[descriptor] |= TxHostOwns;
     s->TxStatus[descriptor] |= TxStatOK;
 
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: +++ transmitted %d bytes from descriptor %d\n", txsize, 
descriptor);
-#endif
+    rtl8139_transfer_frame(s, txbuffer, txsize, 0);
+
+    DEBUG_PRINT(("RTL8139: +++ transmitted %d bytes from descriptor %d\n", 
txsize, descriptor));
 
     /* update interrupt */
     s->IntrStatus |= TxOK;
@@ -1639,21 +1801,104 @@ static int rtl8139_transmit_one(RTL8139S
     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))
     {
-#ifdef DEBUG_RTL8139
-        printf("RTL8139: +++ C+ mode: transmitter disabled\n");
-#endif
+        DEBUG_PRINT(("RTL8139: +++ C+ mode: transmitter disabled\n"));
         return 0;
     }
 
     if (!rtl8139_cp_transmitter_enabled(s))
     {
-#ifdef DEBUG_RTL8139
-        printf("RTL8139: +++ C+ mode: C+ transmitter disabled\n");
-#endif
+        DEBUG_PRINT(("RTL8139: +++ C+ mode: C+ transmitter disabled\n"));
         return 0 ;
     }
 
@@ -1665,10 +1910,8 @@ static int rtl8139_cplus_transmit_one(RT
     /* Normal priority ring */
     cplus_tx_ring_desc += 16 * descriptor;
 
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: +++ C+ mode reading TX descriptor %d from host memory at 
%08x0x%08x = 0x%8lx\n",
-           descriptor, s->TxAddr[1], s->TxAddr[0], cplus_tx_ring_desc);
-#endif
+    DEBUG_PRINT(("RTL8139: +++ C+ mode reading TX descriptor %d from host 
memory at %08x0x%08x = 0x%8lx\n",
+           descriptor, s->TxAddr[1], s->TxAddr[0], cplus_tx_ring_desc));
 
     uint32_t val, txdw0,txdw1,txbufLO,txbufHI;
 
@@ -1681,11 +1924,9 @@ static int rtl8139_cplus_transmit_one(RT
     cpu_physical_memory_read(cplus_tx_ring_desc+12, (uint8_t *)&val, 4);
     txbufHI = le32_to_cpu(val);
 
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: +++ C+ mode TX descriptor %d %08x %08x %08x %08x\n",
+    DEBUG_PRINT(("RTL8139: +++ C+ mode TX descriptor %d %08x %08x %08x %08x\n",
            descriptor,
-           txdw0, txdw1, txbufLO, txbufHI);
-#endif
+           txdw0, txdw1, txbufLO, txbufHI));
 
 /* w0 ownership flag */
 #define CP_TX_OWN (1<<31)
@@ -1697,6 +1938,9 @@ static int rtl8139_cplus_transmit_one(RT
 #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 */
@@ -1728,28 +1972,73 @@ static int rtl8139_cplus_transmit_one(RT
 
     if (!(txdw0 & CP_TX_OWN))
     {
-#if defined(DEBUG_RTL8139)
-        printf("RTL8139: C+ Tx mode : descriptor %d is owned by host\n", 
descriptor);
-#endif
+        DEBUG_PRINT(("RTL8139: C+ Tx mode : descriptor %d is owned by host\n", 
descriptor));
         return 0 ;
     }
 
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: +++ C+ Tx mode : transmitting from descriptor %d\n", 
descriptor);
-#endif
+    DEBUG_PRINT(("RTL8139: +++ C+ Tx mode : transmitting from descriptor 
%d\n", descriptor));
+
+    if (txdw0 & CP_TX_FS)
+    {
+        DEBUG_PRINT(("RTL8139: +++ 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;
     target_phys_addr_t tx_addr = rtl8139_addr64(txbufLO, txbufHI);
 
-    uint8_t txbuffer[CP_TX_BUFFER_SIZE];
-
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: +++ C+ mode transmit reading %d bytes from host memory at 
0x%08x\n", txsize, tx_addr);
-#endif
-    cpu_physical_memory_read(tx_addr, txbuffer, txsize);
-
-    /* transmit the packet */
-    qemu_send_packet(s->vc, txbuffer, txsize);
+    /* 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 = malloc(s->cplus_txbuffer_len);
+        s->cplus_txbuffer_offset = 0;
+
+        DEBUG_PRINT(("RTL8139: +++ C+ mode transmission buffer allocated space 
%d\n", s->cplus_txbuffer_len));
+    }
+
+    while (s->cplus_txbuffer && s->cplus_txbuffer_offset + txsize >= 
s->cplus_txbuffer_len)
+    {
+        s->cplus_txbuffer_len += CP_TX_BUFFER_SIZE;
+        s->cplus_txbuffer = realloc(s->cplus_txbuffer, s->cplus_txbuffer_len);
+
+        DEBUG_PRINT(("RTL8139: +++ C+ mode transmission buffer space changed 
to %d\n", s->cplus_txbuffer_len));
+    }
+
+    if (!s->cplus_txbuffer)
+    {
+        /* out of memory */
+
+        DEBUG_PRINT(("RTL8139: +++ 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 */
+
+    DEBUG_PRINT(("RTL8139: +++ C+ mode transmit reading %d bytes from host 
memory at %016" PRIx64 " to offset %d\n",
+                 txsize, (uint64_t)tx_addr, s->cplus_txbuffer_offset));
+
+    cpu_physical_memory_read(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;
@@ -1767,19 +2056,266 @@ static int rtl8139_cplus_transmit_one(RT
 //    val = cpu_to_le32(txdw1);
 //    cpu_physical_memory_write(cplus_tx_ring_desc+4,  &val, 4);
 
-    /* seek to next Rx descriptor */
-    if (txdw0 & CP_TX_EOR)
-    {
-        s->currCPlusTxDesc = 0;
+    /* Now decide if descriptor being processed is holding the last segment of 
packet */
+    if (txdw0 & CP_TX_LS)
+    {
+        DEBUG_PRINT(("RTL8139: +++ 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;
+
+        /* 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))
+        {
+            DEBUG_PRINT(("RTL8139: +++ C+ mode offloaded task checksum\n"));
+
+            #define ETH_P_IP   0x0800          /* Internet Protocol packet     
*/
+            #define ETH_HLEN    14
+            #define ETH_MTU     1500
+
+            /* ip packet header */
+            ip_header *ip = 0;
+            int hlen = 0;
+            uint8_t  ip_protocol = 0;
+            uint16_t ip_data_len = 0;
+
+            uint8_t *eth_payload_data = 0;
+            size_t   eth_payload_len  = 0;
+
+            int proto = be16_to_cpu(*(uint16_t *)(saved_buffer + 12));
+            if (proto == ETH_P_IP)
+            {
+                DEBUG_PRINT(("RTL8139: +++ 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) {
+                    DEBUG_PRINT(("RTL8139: +++ 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)
+                {
+                    DEBUG_PRINT(("RTL8139: +++ 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);
+                        DEBUG_PRINT(("RTL8139: +++ C+ mode IP header len=%d 
checksum=%04x\n", hlen, ip->ip_sum));
+                    }
+                }
+
+                if ((txdw0 & CP_TX_LGSEN) && ip_protocol == IP_PROTO_TCP)
+                {
+#if defined (DEBUG_RTL8139)
+                    int large_send_mss = (txdw0 >> 16) & CP_TC_LGSEN_MSS_MASK;
+#endif
+                    DEBUG_PRINT(("RTL8139: +++ 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;
+
+                    DEBUG_PRINT(("RTL8139: +++ 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;
+                        }
+
+                        DEBUG_PRINT(("RTL8139: +++ 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);
+
+                        DEBUG_PRINT(("RTL8139: +++ 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);
+                        DEBUG_PRINT(("RTL8139: +++ 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);
+                        DEBUG_PRINT(("RTL8139: +++ 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;
+                        DEBUG_PRINT(("RTL8139: +++ C+ mode TSO transferring 
packet size %d\n", tso_send_size));
+                        rtl8139_transfer_frame(s, saved_buffer, tso_send_size, 
0);
+
+                        /* 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))
+                {
+                    DEBUG_PRINT(("RTL8139: +++ 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)
+                    {
+                        DEBUG_PRINT(("RTL8139: +++ 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);
+                        DEBUG_PRINT(("RTL8139: +++ 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)
+                    {
+                        DEBUG_PRINT(("RTL8139: +++ 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);
+                        DEBUG_PRINT(("RTL8139: +++ 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;
+
+        DEBUG_PRINT(("RTL8139: +++ C+ mode transmitting %d bytes packet\n", 
saved_size));
+
+        rtl8139_transfer_frame(s, saved_buffer, saved_size, 1);
+
+        /* 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
+        {
+            free(saved_buffer);
+        }
     }
     else
     {
-        ++s->currCPlusTxDesc;
-    }
-
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: +++ C+ mode transmitted %d bytes from descriptor %d\n", 
txsize, descriptor);
-#endif
+        DEBUG_PRINT(("RTL8139: +++ C+ mode transmission continue to next 
descriptor\n"));
+    }
+
     return 1;
 }
 
@@ -1795,9 +2331,8 @@ static void rtl8139_cplus_transmit(RTL81
     /* Mark transfer completed */
     if (!txcount)
     {
-#ifdef DEBUG_RTL8139
-        printf("RTL8139: C+ mode : transmitter queue stalled, current TxDesc = 
%d\n", s->currCPlusTxDesc);
-#endif
+        DEBUG_PRINT(("RTL8139: C+ mode : transmitter queue stalled, current 
TxDesc = %d\n",
+                     s->currCPlusTxDesc));
     }
     else
     {
@@ -1822,9 +2357,7 @@ static void rtl8139_transmit(RTL8139Stat
     /* Mark transfer completed */
     if (!txcount)
     {
-#ifdef DEBUG_RTL8139
-        printf("RTL8139: transmitter queue stalled, current TxDesc = %d\n", 
s->currTxDesc);
-#endif
+        DEBUG_PRINT(("RTL8139: transmitter queue stalled, current TxDesc = 
%d\n", s->currTxDesc));
     }
 }
 
@@ -1832,9 +2365,31 @@ static void rtl8139_TxStatus_write(RTL81
 {
 
     int descriptor = txRegOffset/4;
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: TxStatus write offset=0x%x val=0x%08x descriptor=%d\n", 
txRegOffset, val, descriptor);
-#endif
+
+    /* handle C+ transmit mode register configuration */
+
+    if (rtl8139_cp_transmitter_enabled(s))
+    {
+        DEBUG_PRINT(("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))
+        {
+            target_phys_addr_t tc_addr = rtl8139_addr64(s->TxStatus[0] & 
~0x3f, s->TxStatus[1]);
+
+            /* dump tally counters to specified memory location */
+            RTL8139TallyCounters_physical_memory_write( tc_addr, 
&s->tally_counters);
+
+            /* mark dump completed */
+            s->TxStatus[0] &= ~0x8;
+        }
+
+        return;
+    }
+
+    DEBUG_PRINT(("RTL8139: 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 */
@@ -1850,9 +2405,7 @@ static uint32_t rtl8139_TxStatus_read(RT
 {
     uint32_t ret = s->TxStatus[txRegOffset/4];
 
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: TxStatus read offset=0x%x val=0x%08x\n", txRegOffset, 
ret);
-#endif
+    DEBUG_PRINT(("RTL8139: TxStatus read offset=0x%x val=0x%08x\n", 
txRegOffset, ret));
 
     return ret;
 }
@@ -1884,9 +2437,7 @@ static uint16_t rtl8139_TSAD_read(RTL813
          |((s->TxStatus[0] & TxHostOwns )?TSAD_OWN0:0) ;
        
 
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: TSAD read val=0x%04x\n", ret);
-#endif
+    DEBUG_PRINT(("RTL8139: TSAD read val=0x%04x\n", ret));
 
     return ret;
 }
@@ -1895,18 +2446,14 @@ static uint16_t rtl8139_CSCR_read(RTL813
 {
     uint16_t ret = s->CSCR;
 
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: CSCR read val=0x%04x\n", ret);
-#endif
+    DEBUG_PRINT(("RTL8139: CSCR read val=0x%04x\n", ret));
 
     return ret;
 }
 
 static void rtl8139_TxAddr_write(RTL8139State *s, uint32_t txAddrOffset, 
uint32_t val)
 {
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: TxAddr write offset=0x%x val=0x%08x\n", txAddrOffset, 
val);
-#endif
+    DEBUG_PRINT(("RTL8139: TxAddr write offset=0x%x val=0x%08x\n", 
txAddrOffset, val));
 
     s->TxAddr[txAddrOffset/4] = le32_to_cpu(val);
 }
@@ -1915,26 +2462,20 @@ static uint32_t rtl8139_TxAddr_read(RTL8
 {
     uint32_t ret = cpu_to_le32(s->TxAddr[txAddrOffset/4]);
 
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: TxAddr read offset=0x%x val=0x%08x\n", txAddrOffset, ret);
-#endif
+    DEBUG_PRINT(("RTL8139: TxAddr read offset=0x%x val=0x%08x\n", 
txAddrOffset, ret));
 
     return ret;
 }
 
 static void rtl8139_RxBufPtr_write(RTL8139State *s, uint32_t val)
 {
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: RxBufPtr write val=0x%04x\n", val);
-#endif
+    DEBUG_PRINT(("RTL8139: RxBufPtr write val=0x%04x\n", val));
 
     /* this value is off by 16 */
     s->RxBufPtr = MOD2(val + 0x10, s->RxBufferSize);
 
-#if defined(DEBUG_RTL8139)
-    printf(" CAPR write: rx buffer length %d head 0x%04x read 0x%04x\n",
-           s->RxBufferSize, s->RxBufAddr, s->RxBufPtr);
-#endif
+    DEBUG_PRINT((" 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)
@@ -1942,18 +2483,24 @@ static uint32_t rtl8139_RxBufPtr_read(RT
     /* this value is off by 16 */
     uint32_t ret = s->RxBufPtr - 0x10;
 
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: RxBufPtr read val=0x%04x\n", ret);
-#endif
+    DEBUG_PRINT(("RTL8139: 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;
+
+    DEBUG_PRINT(("RTL8139: RxBufAddr read val=0x%04x\n", ret));
+
+    return ret;
+}
+
 static void rtl8139_RxBuf_write(RTL8139State *s, uint32_t val)
 {
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: RxBuf write val=0x%08x\n", val);
-#endif
+    DEBUG_PRINT(("RTL8139: RxBuf write val=0x%08x\n", val));
 
     s->RxBuf = val;
 
@@ -1964,18 +2511,14 @@ static uint32_t rtl8139_RxBuf_read(RTL81
 {
     uint32_t ret = s->RxBuf;
 
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: RxBuf read val=0x%08x\n", ret);
-#endif
+    DEBUG_PRINT(("RTL8139: RxBuf read val=0x%08x\n", ret));
 
     return ret;
 }
 
 static void rtl8139_IntrMask_write(RTL8139State *s, uint32_t val)
 {
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: IntrMask write(w) val=0x%04x\n", val);
-#endif
+    DEBUG_PRINT(("RTL8139: IntrMask write(w) val=0x%04x\n", val));
 
     /* mask unwriteable bits */
     val = SET_MASKED(val, 0x1e00, s->IntrMask);
@@ -1989,18 +2532,14 @@ static uint32_t rtl8139_IntrMask_read(RT
 {
     uint32_t ret = s->IntrMask;
 
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: IntrMask read(w) val=0x%04x\n", ret);
-#endif
+    DEBUG_PRINT(("RTL8139: IntrMask read(w) val=0x%04x\n", ret));
 
     return ret;
 }
 
 static void rtl8139_IntrStatus_write(RTL8139State *s, uint32_t val)
 {
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: IntrStatus write(w) val=0x%04x\n", val);
-#endif
+    DEBUG_PRINT(("RTL8139: IntrStatus write(w) val=0x%04x\n", val));
 
 #if 0
 
@@ -2027,9 +2566,7 @@ static uint32_t rtl8139_IntrStatus_read(
 {
     uint32_t ret = s->IntrStatus;
 
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: IntrStatus read(w) val=0x%04x\n", ret);
-#endif
+    DEBUG_PRINT(("RTL8139: IntrStatus read(w) val=0x%04x\n", ret));
 
 #if 0
 
@@ -2045,9 +2582,7 @@ static uint32_t rtl8139_IntrStatus_read(
 
 static void rtl8139_MultiIntr_write(RTL8139State *s, uint32_t val)
 {
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: MultiIntr write(w) val=0x%04x\n", val);
-#endif
+    DEBUG_PRINT(("RTL8139: MultiIntr write(w) val=0x%04x\n", val));
 
     /* mask unwriteable bits */
     val = SET_MASKED(val, 0xf000, s->MultiIntr);
@@ -2059,9 +2594,7 @@ static uint32_t rtl8139_MultiIntr_read(R
 {
     uint32_t ret = s->MultiIntr;
 
-#ifdef DEBUG_RTL8139
-    printf("RTL8139: MultiIntr read(w) val=0x%04x\n", ret);
-#endif
+    DEBUG_PRINT(("RTL8139: MultiIntr read(w) val=0x%04x\n", ret));
 
     return ret;
 }
@@ -2109,15 +2642,11 @@ static void rtl8139_io_writeb(void *opaq
             break;
         case MediaStatus:
             /* ignore */
-#ifdef DEBUG_RTL8139
-            printf("RTL8139: not implemented write(b) to MediaStatus 
val=0x%02x\n", val);
-#endif
+            DEBUG_PRINT(("RTL8139: not implemented write(b) to MediaStatus 
val=0x%02x\n", val));
             break;
 
         case HltClk:
-#ifdef DEBUG_RTL8139
-            printf("RTL8139: HltClk write val=0x%08x\n", val);
-#endif
+            DEBUG_PRINT(("RTL8139: HltClk write val=0x%08x\n", val));
             if (val == 'R')
             {
                 s->clock_enabled = 1;
@@ -2129,37 +2658,27 @@ static void rtl8139_io_writeb(void *opaq
             break;
 
         case TxThresh:
-#ifdef DEBUG_RTL8139
-            printf("RTL8139C+ TxThresh write(b) val=0x%02x\n", val);
-#endif
+            DEBUG_PRINT(("RTL8139C+ TxThresh write(b) val=0x%02x\n", val));
             s->TxThresh = val;
             break;
 
         case TxPoll:
-#ifdef DEBUG_RTL8139
-                printf("RTL8139C+ TxPoll write(b) val=0x%02x\n", val);
-#endif
+            DEBUG_PRINT(("RTL8139C+ TxPoll write(b) val=0x%02x\n", val));
             if (val & (1 << 7))
             {
-#ifdef DEBUG_RTL8139
-                printf("RTL8139C+ TxPoll high priority transmission (not 
implemented)\n");
-#endif
+                DEBUG_PRINT(("RTL8139C+ TxPoll high priority transmission (not 
implemented)\n"));
                 //rtl8139_cplus_transmit(s);
             }
             if (val & (1 << 6))
             {
-#ifdef DEBUG_RTL8139
-                printf("RTL8139C+ TxPoll normal priority transmission\n");
-#endif
+                DEBUG_PRINT(("RTL8139C+ TxPoll normal priority 
transmission\n"));
                 rtl8139_cplus_transmit(s);
             }
 
             break;
 
         default:
-#ifdef DEBUG_RTL8139
-            printf("RTL8139: not implemented write(b) addr=0x%x val=0x%02x\n", 
addr, val);
-#endif
+            DEBUG_PRINT(("RTL8139: not implemented write(b) addr=0x%x 
val=0x%02x\n", addr, val));
             break;
     }
 }
@@ -2195,20 +2714,14 @@ static void rtl8139_io_writew(void *opaq
             rtl8139_BasicModeStatus_write(s, val);
             break;
         case NWayAdvert:
-#ifdef DEBUG_RTL8139
-            printf("RTL8139: NWayAdvert write(w) val=0x%04x\n", val);
-#endif
+            DEBUG_PRINT(("RTL8139: NWayAdvert write(w) val=0x%04x\n", val));
             s->NWayAdvert = val;
             break;
         case NWayLPAR:
-#ifdef DEBUG_RTL8139
-            printf("RTL8139: forbidden NWayLPAR write(w) val=0x%04x\n", val);
-#endif
+            DEBUG_PRINT(("RTL8139: forbidden NWayLPAR write(w) val=0x%04x\n", 
val));
             break;
         case NWayExpansion:
-#ifdef DEBUG_RTL8139
-            printf("RTL8139: NWayExpansion write(w) val=0x%04x\n", val);
-#endif
+            DEBUG_PRINT(("RTL8139: NWayExpansion write(w) val=0x%04x\n", val));
             s->NWayExpansion = val;
             break;
 
@@ -2216,10 +2729,12 @@ static void rtl8139_io_writew(void *opaq
             rtl8139_CpCmd_write(s, val);
             break;
 
+        case IntrMitigate:
+            rtl8139_IntrMitigate_write(s, val);
+            break;
+
         default:
-#ifdef DEBUG_RTL8139
-            printf("RTL8139: ioport write(w) addr=0x%x val=0x%04x via 
write(b)\n", addr, val);
-#endif
+            DEBUG_PRINT(("RTL8139: ioport write(w) addr=0x%x val=0x%04x via 
write(b)\n", addr, val));
 
 #ifdef TARGET_WORDS_BIGENDIAN
             rtl8139_io_writeb(opaque, addr, (val >> 8) & 0xff);
@@ -2241,9 +2756,7 @@ static void rtl8139_io_writel(void *opaq
     switch (addr)
     {
         case RxMissed:
-#ifdef DEBUG_RTL8139
-            printf("RTL8139: RxMissed clearing on write\n");
-#endif
+            DEBUG_PRINT(("RTL8139: RxMissed clearing on write\n"));
             s->RxMissed = 0;
             break;
 
@@ -2268,23 +2781,28 @@ static void rtl8139_io_writel(void *opaq
             break;
 
         case RxRingAddrLO:
-#ifdef DEBUG_RTL8139
-            printf("RTL8139: C+ RxRing low bits write val=0x%08x\n", val);
-#endif
+            DEBUG_PRINT(("RTL8139: C+ RxRing low bits write val=0x%08x\n", 
val));
             s->RxRingAddrLO = val;
             break;
 
         case RxRingAddrHI:
-#ifdef DEBUG_RTL8139
-            printf("RTL8139: C+ RxRing high bits write val=0x%08x\n", val);
-#endif
+            DEBUG_PRINT(("RTL8139: C+ RxRing high bits write val=0x%08x\n", 
val));
             s->RxRingAddrHI = val;
             break;
 
+        case Timer:
+            DEBUG_PRINT(("RTL8139: TCTR Timer reset on write\n"));
+            s->TCTR = 0;
+            s->TCTR_base = qemu_get_clock(vm_clock);
+            break;
+
+        case FlashReg:
+            DEBUG_PRINT(("RTL8139: FlashReg TimerInt write val=0x%08x\n", 
val));
+            s->TimerInt = val;
+            break;
+
         default:
-#ifdef DEBUG_RTL8139
-            printf("RTL8139: ioport write(l) addr=0x%x val=0x%08x via 
write(b)\n", addr, val);
-#endif
+            DEBUG_PRINT(("RTL8139: ioport write(l) addr=0x%x val=0x%08x via 
write(b)\n", addr, val));
 #ifdef TARGET_WORDS_BIGENDIAN
             rtl8139_io_writeb(opaque, addr, (val >> 24) & 0xff);
             rtl8139_io_writeb(opaque, addr + 1, (val >> 16) & 0xff);
@@ -2342,43 +2860,31 @@ static uint32_t rtl8139_io_readb(void *o
 
         case MediaStatus:
             ret = 0xd0;
-#ifdef DEBUG_RTL8139
-            printf("RTL8139: MediaStatus read 0x%x\n", ret);
-#endif
+            DEBUG_PRINT(("RTL8139: MediaStatus read 0x%x\n", ret));
             break;
 
         case HltClk:
             ret = s->clock_enabled;
-#ifdef DEBUG_RTL8139
-            printf("RTL8139: HltClk read 0x%x\n", ret);
-#endif
+            DEBUG_PRINT(("RTL8139: HltClk read 0x%x\n", ret));
             break;
 
         case PCIRevisionID:
-            ret = 0x10;
-#ifdef DEBUG_RTL8139
-            printf("RTL8139: PCI Revision ID read 0x%x\n", ret);
-#endif
+            ret = RTL8139_PCI_REVID;
+            DEBUG_PRINT(("RTL8139: PCI Revision ID read 0x%x\n", ret));
             break;
 
         case TxThresh:
             ret = s->TxThresh;
-#ifdef DEBUG_RTL8139
-            printf("RTL8139C+ TxThresh read(b) val=0x%02x\n", ret);
-#endif
+            DEBUG_PRINT(("RTL8139C+ 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;
-#ifdef DEBUG_RTL8139
-            printf("RTL8139C TxConfig at 0x43 read(b) val=0x%02x\n", ret);
-#endif
+            DEBUG_PRINT(("RTL8139C TxConfig at 0x43 read(b) val=0x%02x\n", 
ret));
             break;
 
         default:
-#ifdef DEBUG_RTL8139
-            printf("RTL8139: not implemented read(b) addr=0x%x\n", addr);
-#endif
+            DEBUG_PRINT(("RTL8139: not implemented read(b) addr=0x%x\n", 
addr));
             ret = 0;
             break;
     }
@@ -2411,6 +2917,10 @@ static uint32_t rtl8139_io_readw(void *o
             ret = rtl8139_RxBufPtr_read(s);
             break;
 
+        case RxBufAddr:
+            ret = rtl8139_RxBufAddr_read(s);
+            break;
+
         case BasicModeCtrl:
             ret = rtl8139_BasicModeCtrl_read(s);
             break;
@@ -2419,27 +2929,25 @@ static uint32_t rtl8139_io_readw(void *o
             break;
         case NWayAdvert:
             ret = s->NWayAdvert;
-#ifdef DEBUG_RTL8139
-            printf("RTL8139: NWayAdvert read(w) val=0x%04x\n", ret);
-#endif
+            DEBUG_PRINT(("RTL8139: NWayAdvert read(w) val=0x%04x\n", ret));
             break;
         case NWayLPAR:
             ret = s->NWayLPAR;
-#ifdef DEBUG_RTL8139
-            printf("RTL8139: NWayLPAR read(w) val=0x%04x\n", ret);
-#endif
+            DEBUG_PRINT(("RTL8139: NWayLPAR read(w) val=0x%04x\n", ret));
             break;
         case NWayExpansion:
             ret = s->NWayExpansion;
-#ifdef DEBUG_RTL8139
-            printf("RTL8139: NWayExpansion read(w) val=0x%04x\n", ret);
-#endif
+            DEBUG_PRINT(("RTL8139: 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;
@@ -2449,9 +2957,7 @@ static uint32_t rtl8139_io_readw(void *o
             break;
 
         default:
-#ifdef DEBUG_RTL8139
-            printf("RTL8139: ioport read(w) addr=0x%x via read(b)\n", addr);
-#endif
+            DEBUG_PRINT(("RTL8139: ioport read(w) addr=0x%x via read(b)\n", 
addr));
 
 #ifdef TARGET_WORDS_BIGENDIAN
             ret  = rtl8139_io_readb(opaque, addr) << 8;
@@ -2461,9 +2967,7 @@ static uint32_t rtl8139_io_readw(void *o
             ret |= rtl8139_io_readb(opaque, addr + 1) << 8;
 #endif
 
-#ifdef DEBUG_RTL8139
-            printf("RTL8139: ioport read(w) addr=0x%x val=0x%04x\n", addr, 
ret);
-#endif
+            DEBUG_PRINT(("RTL8139: ioport read(w) addr=0x%x val=0x%04x\n", 
addr, ret));
             break;
     }
 
@@ -2482,9 +2986,7 @@ static uint32_t rtl8139_io_readl(void *o
         case RxMissed:
             ret = s->RxMissed;
 
-#ifdef DEBUG_RTL8139
-            printf("RTL8139: RxMissed read val=0x%08x\n", ret);
-#endif
+            DEBUG_PRINT(("RTL8139: RxMissed read val=0x%08x\n", ret));
             break;
 
         case TxConfig:
@@ -2509,22 +3011,26 @@ static uint32_t rtl8139_io_readl(void *o
 
         case RxRingAddrLO:
             ret = s->RxRingAddrLO;
-#ifdef DEBUG_RTL8139
-            printf("RTL8139: C+ RxRing low bits read val=0x%08x\n", ret);
-#endif
+            DEBUG_PRINT(("RTL8139: C+ RxRing low bits read val=0x%08x\n", 
ret));
             break;
 
         case RxRingAddrHI:
             ret = s->RxRingAddrHI;
-#ifdef DEBUG_RTL8139
-            printf("RTL8139: C+ RxRing high bits read val=0x%08x\n", ret);
-#endif
+            DEBUG_PRINT(("RTL8139: C+ RxRing high bits read val=0x%08x\n", 
ret));
+            break;
+
+        case Timer:
+            ret = s->TCTR;
+            DEBUG_PRINT(("RTL8139: TCTR Timer read val=0x%08x\n", ret));
+            break;
+
+        case FlashReg:
+            ret = s->TimerInt;
+            DEBUG_PRINT(("RTL8139: FlashReg TimerInt read val=0x%08x\n", ret));
             break;
 
         default:
-#ifdef DEBUG_RTL8139
-            printf("RTL8139: ioport read(l) addr=0x%x via read(b)\n", addr);
-#endif
+            DEBUG_PRINT(("RTL8139: ioport read(l) addr=0x%x via read(b)\n", 
addr));
 
 #ifdef TARGET_WORDS_BIGENDIAN
             ret  = rtl8139_io_readb(opaque, addr) << 24;
@@ -2538,9 +3044,7 @@ static uint32_t rtl8139_io_readl(void *o
             ret |= rtl8139_io_readb(opaque, addr + 3) << 24;
 #endif
 
-#ifdef DEBUG_RTL8139
-            printf("RTL8139: read(l) addr=0x%x val=%08x\n", addr, ret);
-#endif
+            DEBUG_PRINT(("RTL8139: read(l) addr=0x%x val=%08x\n", addr, ret));
             break;
     }
 
@@ -2688,6 +3192,12 @@ static void rtl8139_save(QEMUFile* f,voi
     qemu_put_8s(f, &s->eeprom.eesk);
     qemu_put_8s(f, &s->eeprom.eedi);
     qemu_put_8s(f, &s->eeprom.eedo);
+
+    qemu_put_be32s(f, &s->TCTR);
+    qemu_put_be32s(f, &s->TimerInt);
+    qemu_put_be64s(f, &s->TCTR_base);
+
+    RTL8139TallyCounters_save(f, &s->tally_counters);
 }
 
 static int rtl8139_load(QEMUFile* f,void* opaque,int version_id)
@@ -2695,9 +3205,11 @@ static int rtl8139_load(QEMUFile* f,void
     RTL8139State* s=(RTL8139State*)opaque;
     int i;
 
-    if (version_id != 1)
+    /* just 2 versions for now */
+    if (version_id > 2)
             return -EINVAL;
 
+    /* saved since version 1 */
     qemu_get_buffer(f, s->phys, 6);
     qemu_get_buffer(f, s->mult, 8);
 
@@ -2769,6 +3281,25 @@ static int rtl8139_load(QEMUFile* f,void
     qemu_get_8s(f, &s->eeprom.eedi);
     qemu_get_8s(f, &s->eeprom.eedo);
 
+    /* saved since version 2 */
+    if (version_id >= 2)
+    {
+        qemu_get_be32s(f, &s->TCTR);
+        qemu_get_be32s(f, &s->TimerInt);
+        qemu_get_be64s(f, &s->TCTR_base);
+
+        RTL8139TallyCounters_load(f, &s->tally_counters);
+    }
+    else
+    {
+        /* not saved, use default */
+        s->TCTR = 0;
+        s->TimerInt = 0;
+        s->TCTR_base = 0;
+
+        RTL8139TallyCounters_clear(&s->tally_counters);
+    }
+
     return 0;
 }
 
@@ -2816,6 +3347,59 @@ static CPUWriteMemoryFunc *rtl8139_mmio_
     rtl8139_mmio_writew,
     rtl8139_mmio_writel,
 };
+
+static inline int64_t rtl8139_get_next_tctr_time(RTL8139State *s, int64_t 
current_time)
+{
+    int64_t next_time = current_time + 
+        muldiv64(1, ticks_per_sec, PCI_FREQUENCY);
+    if (next_time <= current_time)
+        next_time = current_time + 1;
+    return next_time;
+}
+
+#if RTL8139_ONBOARD_TIMER
+static void rtl8139_timer(void *opaque)
+{
+    RTL8139State *s = opaque;
+
+    int is_timeout = 0;
+
+    int64_t  curr_time;
+    uint32_t curr_tick;
+
+    if (!s->clock_enabled)
+    {
+        DEBUG_PRINT(("RTL8139: >>> timer: clock is not running\n"));
+        return;
+    }
+
+    curr_time = qemu_get_clock(vm_clock);
+
+    curr_tick = muldiv64(curr_time - s->TCTR_base, PCI_FREQUENCY, 
ticks_per_sec);
+
+    if (s->TimerInt && curr_tick >= s->TimerInt)
+    {
+        if (s->TCTR < s->TimerInt || curr_tick < s->TCTR)
+        {
+            is_timeout = 1;
+        }
+    }
+
+    s->TCTR = curr_tick;
+
+//  DEBUG_PRINT(("RTL8139: >>> timer: tick=%08u\n", s->TCTR));
+
+    if (is_timeout)
+    {
+        DEBUG_PRINT(("RTL8139: >>> timer: timeout tick=%08u\n", s->TCTR));
+        s->IntrStatus |= PCSTimeout;
+        rtl8139_update_irq(s);
+    }
+
+    qemu_mod_timer(s->timer, 
+        rtl8139_get_next_tctr_time(s,curr_time));
+}
+#endif /* RTL8139_ONBOARD_TIMER */
 
 void pci_rtl8139_init(PCIBus *bus, NICInfo *nd)
 {
@@ -2833,7 +3417,7 @@ void pci_rtl8139_init(PCIBus *bus, NICIn
     pci_conf[0x02] = 0x39;
     pci_conf[0x03] = 0x81;
     pci_conf[0x04] = 0x05; /* command = I/O space, Bus Master */
-    pci_conf[0x08] = 0x20; /* 0x10 */ /* PCI revision ID; >=0x20 is for 8139C+ 
*/
+    pci_conf[0x08] = RTL8139_PCI_REVID; /* PCI revision ID; >=0x20 is for 
8139C+ */
     pci_conf[0x0a] = 0x00; /* ethernet network controller */
     pci_conf[0x0b] = 0x02;
     pci_conf[0x0e] = 0x00; /* header_type */
@@ -2867,9 +3451,21 @@ void pci_rtl8139_init(PCIBus *bus, NICIn
              s->macaddr[3],
              s->macaddr[4],
              s->macaddr[5]);
+
+    s->cplus_txbuffer = NULL;
+    s->cplus_txbuffer_len = 0;
+    s->cplus_txbuffer_offset = 0;
              
     /* XXX: instance number ? */
-    register_savevm("rtl8139", 0, 1, rtl8139_save, rtl8139_load, s);
+    register_savevm("rtl8139", 0, 2, rtl8139_save, rtl8139_load, s);
     register_savevm("rtl8139_pci", 0, 1, generic_pci_save, generic_pci_load, 
                     &d->dev);
-}
+
+#if RTL8139_ONBOARD_TIMER
+    s->timer = qemu_new_timer(vm_clock, rtl8139_timer, s);
+
+    qemu_mod_timer(s->timer, 
+        rtl8139_get_next_tctr_time(s,qemu_get_clock(vm_clock)));
+#endif /* RTL8139_ONBOARD_TIMER */
+}
+
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/sb16.c
--- a/tools/ioemu/hw/sb16.c     Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/hw/sb16.c     Mon Aug 07 18:25:30 2006 +0100
@@ -193,6 +193,31 @@ static void aux_timer (void *opaque)
 #define DMA8_AUTO 1
 #define DMA8_HIGH 2
 
+static void continue_dma8 (SB16State *s)
+{
+    if (s->freq > 0) {
+        audsettings_t 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;
@@ -201,7 +226,8 @@ static void dma_cmd8 (SB16State *s, int 
     s->fmt_signed = 0;
     s->fmt_stereo = (s->mixer_regs[0x0e] & 2) != 0;
     if (-1 == s->time_const) {
-        s->freq = 11025;
+        if (s->freq <= 0)
+            s->freq = 11025;
     }
     else {
         int tmp = (256 - s->time_const);
@@ -239,27 +265,7 @@ static void dma_cmd8 (SB16State *s, int 
             s->freq, s->fmt_stereo, s->fmt_signed, s->fmt_bits,
             s->block_size, s->dma_auto, s->fifo, s->highspeed);
 
-    if (s->freq) {
-        audsettings_t as;
-
-        s->audio_free = 0;
-
-        as.freq = s->freq;
-        as.nchannels = 1 << s->fmt_stereo;
-        as.fmt = s->fmt;
-
-        s->voice = AUD_open_out (
-            &s->card,
-            s->voice,
-            "sb16",
-            s,
-            SB_audio_callback,
-            &as,
-            0                   /* little endian */
-            );
-    }
-
-    control (s, 1);
+    continue_dma8 (s);
     speaker (s, 1);
 }
 
@@ -342,6 +348,7 @@ static void dma_cmd (SB16State *s, uint8
         as.freq = s->freq;
         as.nchannels = 1 << s->fmt_stereo;
         as.fmt = s->fmt;
+        as.endianness = 0;
 
         s->voice = AUD_open_out (
             &s->card,
@@ -349,8 +356,7 @@ static void dma_cmd (SB16State *s, uint8
             "sb16",
             s,
             SB_audio_callback,
-            &as,
-            0                   /* little endian */
+            &as
             );
     }
 
@@ -437,7 +443,7 @@ static void command (SB16State *s, uint8
             break;
 
         case 0x1c:              /* Auto-Initialize DMA DAC, 8-bit */
-            control (s, 1);
+            dma_cmd8 (s, DMA8_AUTO, -1);
             break;
 
         case 0x20:              /* Direct ADC, Juice/PL */
@@ -531,7 +537,9 @@ static void command (SB16State *s, uint8
             break;
 
         case 0xd4:              /* continue DMA operation. 8bit */
-            control (s, 1);
+            /* KQ6 (or maybe Sierras audblst.drv in general) resets
+               the frequency between halt/continue */
+            continue_dma8 (s);
             break;
 
         case 0xd5:              /* halt DMA operation. 16bit */
@@ -765,7 +773,7 @@ static void complete (SB16State *s)
                             );
                     }
                 }
-                ldebug ("mix silence %d %d %lld\n", samples, bytes, ticks);
+                ldebug ("mix silence %d %d %" PRId64 "\n", samples, bytes, 
ticks);
             }
             break;
 
@@ -816,6 +824,33 @@ static void complete (SB16State *s)
     ldebug ("\n");
     s->cmd = -1;
     return;
+}
+
+static void legacy_reset (SB16State *s)
+{
+    audsettings_t 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)
@@ -841,6 +876,7 @@ static void reset (SB16State *s)
     dsp_out_data(s, 0xaa);
     speaker (s, 0);
     control (s, 0);
+    legacy_reset (s);
 }
 
 static IO_WRITE_PROTO (dsp_write)
@@ -1335,6 +1371,7 @@ static int SB_load (QEMUFile *f, void *o
             as.freq = s->freq;
             as.nchannels = 1 << s->fmt_stereo;
             as.fmt = s->fmt;
+            as.endianness = 0;
 
             s->voice = AUD_open_out (
                 &s->card,
@@ -1342,8 +1379,7 @@ static int SB_load (QEMUFile *f, void *o
                 "sb16",
                 s,
                 SB_audio_callback,
-                &as,
-                0               /* little endian */
+                &as
                 );
         }
 
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/sh7750.c
--- a/tools/ioemu/hw/sh7750.c   Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/hw/sh7750.c   Mon Aug 07 18:25:30 2006 +0100
@@ -124,7 +124,7 @@ static void start_timer0(SH7750State * s
                       s->periph_freq);
     if (next == now)
        next = now + 1;
-    fprintf(stderr, "now=%016llx, next=%016llx\n", now, next);
+    fprintf(stderr, "now=%016" PRIx64 ", next=%016" PRIx64 "\n", now, next);
     fprintf(stderr, "timer will underflow in %f seconds\n",
            (float) (next - now) / (float) ticks_per_sec);
 
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/slavio_intctl.c
--- a/tools/ioemu/hw/slavio_intctl.c    Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/hw/slavio_intctl.c    Mon Aug 07 18:25:30 2006 +0100
@@ -203,7 +203,7 @@ void slavio_irq_info(void *opaque)
     for (i = 0; i < 32; i++) {
         count = s->irq_count[i];
         if (count > 0)
-            term_printf("%2d: %lld\n", i, count);
+            term_printf("%2d: %" PRId64 "\n", i, count);
     }
 #endif
 }
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/slavio_timer.c
--- a/tools/ioemu/hw/slavio_timer.c     Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/hw/slavio_timer.c     Mon Aug 07 18:25:30 2006 +0100
@@ -100,7 +100,7 @@ static void slavio_timer_get_out(SLAVIO_
     // Convert remaining counter ticks to CPU ticks
     s->expire_time = ticks + muldiv64(limit - count, ticks_per_sec, CNT_FREQ);
 
-    DPRINTF("irq %d limit %d reached %d d %lld count %d s->c %x diff %lld 
stopped %d mode %d\n", s->irq, limit, s->reached?1:0, 
(ticks-s->count_load_time), count, s->count, s->expire_time - ticks, 
s->stopped, s->mode);
+    DPRINTF("irq %d limit %d reached %d d %" PRId64 " count %d s->c %x diff %" 
PRId64 " stopped %d mode %d\n", s->irq, limit, s->reached?1:0, 
(ticks-s->count_load_time), count, s->count, s->expire_time - ticks, 
s->stopped, s->mode);
 
     if (s->mode != 1)
        pic_set_irq_cpu(s->irq, out, s->cpu);
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/sun4m.c
--- a/tools/ioemu/hw/sun4m.c    Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/hw/sun4m.c    Mon Aug 07 18:25:30 2006 +0100
@@ -28,8 +28,7 @@
 #define INITRD_LOAD_ADDR     0x00800000
 #define PROM_SIZE_MAX        (256 * 1024)
 #define PROM_ADDR           0xffd00000
-#define PROM_FILENAMEB      "proll.bin"
-#define PROM_FILENAMEE      "proll.elf"
+#define PROM_FILENAME       "openbios-sparc32"
 #define PHYS_JJ_EEPROM 0x71200000      /* m48t08 */
 #define PHYS_JJ_IDPROM_OFF     0x1FD8
 #define PHYS_JJ_EEPROM_SIZE    0x2000
@@ -183,6 +182,11 @@ void pic_set_irq(int irq, int level)
     slavio_pic_set_irq(slavio_intctl, irq, level);
 }
 
+void pic_set_irq_new(void *opaque, int irq, int level)
+{
+    pic_set_irq(irq, level);
+}
+
 void pic_set_irq_cpu(int irq, int level, unsigned int cpu)
 {
     slavio_pic_set_irq_cpu(slavio_intctl, irq, level, cpu);
@@ -268,12 +272,8 @@ static void sun4m_init(int ram_size, int
                                  (PROM_SIZE_MAX + TARGET_PAGE_SIZE - 1) & 
TARGET_PAGE_MASK, 
                                  prom_offset | IO_MEM_ROM);
 
-    snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEE);
+    snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAME);
     ret = load_elf(buf, 0, NULL);
-    if (ret < 0) {
-       snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEB);
-       ret = load_image(buf, phys_ram_base + prom_offset);
-    }
     if (ret < 0) {
        fprintf(stderr, "qemu: could not load prom '%s'\n", 
                buf);
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/sun4u.c
--- a/tools/ioemu/hw/sun4u.c    Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/hw/sun4u.c    Mon Aug 07 18:25:30 2006 +0100
@@ -27,13 +27,12 @@
 #define KERNEL_LOAD_ADDR     0x00404000
 #define CMDLINE_ADDR         0x003ff000
 #define INITRD_LOAD_ADDR     0x00300000
-#define PROM_SIZE_MAX        (256 * 1024)
+#define PROM_SIZE_MAX        (512 * 1024)
 #define PROM_ADDR           0x1fff0000000ULL
 #define APB_SPECIAL_BASE     0x1fe00000000ULL
 #define APB_MEM_BASE        0x1ff00000000ULL
 #define VGA_BASE            (APB_MEM_BASE + 0x400000ULL)
-#define PROM_FILENAMEB      "proll-sparc64.bin"
-#define PROM_FILENAMEE      "proll-sparc64.elf"
+#define PROM_FILENAME       "openbios-sparc64"
 #define NVRAM_SIZE           0x2000
 
 /* TSC handling */
@@ -282,12 +281,8 @@ static void sun4u_init(int ram_size, int
                                  (PROM_SIZE_MAX + TARGET_PAGE_SIZE) & 
TARGET_PAGE_MASK, 
                                  prom_offset | IO_MEM_ROM);
 
-    snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEE);
+    snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAME);
     ret = load_elf(buf, 0, NULL);
-    if (ret < 0) {
-       snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEB);
-       ret = load_image(buf, phys_ram_base + prom_offset);
-    }
     if (ret < 0) {
        fprintf(stderr, "qemu: could not load prom '%s'\n", 
                buf);
@@ -329,12 +324,9 @@ static void sun4u_init(int ram_size, int
            }
         }
     }
-    pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE);
+    pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, NULL);
     isa_mem_base = VGA_BASE;
-    vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size, 
-                   vga_ram_size, 0, 0);
-    cpu_register_physical_memory(VGA_BASE, vga_ram_size, ram_size);
-    //pci_cirrus_vga_init(pci_bus, ds, phys_ram_base + ram_size, ram_size, 
vga_ram_size);
+    pci_cirrus_vga_init(pci_bus, ds, phys_ram_base + ram_size, ram_size, 
vga_ram_size);
 
     for(i = 0; i < MAX_SERIAL_PORTS; i++) {
         if (serial_hds[i]) {
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/usb-hid.c
--- a/tools/ioemu/hw/usb-hid.c  Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/hw/usb-hid.c  Mon Aug 07 18:25:30 2006 +0100
@@ -500,6 +500,14 @@ static int usb_mouse_handle_data(USBDevi
     return ret;
 }
 
+static void usb_mouse_handle_destroy(USBDevice *dev)
+{
+    USBMouseState *s = (USBMouseState *)dev;
+
+    qemu_add_mouse_event_handler(NULL, NULL, 0);
+    qemu_free(s);
+}
+
 USBDevice *usb_tablet_init(void)
 {
     USBMouseState *s;
@@ -513,7 +521,10 @@ USBDevice *usb_tablet_init(void)
     s->dev.handle_reset = usb_mouse_handle_reset;
     s->dev.handle_control = usb_mouse_handle_control;
     s->dev.handle_data = usb_mouse_handle_data;
+    s->dev.handle_destroy = usb_mouse_handle_destroy;
     s->kind = USB_TABLET;
+
+    pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Tablet");
 
     return (USBDevice *)s;
 }
@@ -531,7 +542,10 @@ USBDevice *usb_mouse_init(void)
     s->dev.handle_reset = usb_mouse_handle_reset;
     s->dev.handle_control = usb_mouse_handle_control;
     s->dev.handle_data = usb_mouse_handle_data;
+    s->dev.handle_destroy = usb_mouse_handle_destroy;
     s->kind = USB_MOUSE;
 
+    pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Mouse");
+
     return (USBDevice *)s;
 }
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/usb-hub.c
--- a/tools/ioemu/hw/usb-hub.c  Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/hw/usb-hub.c  Mon Aug 07 18:25:30 2006 +0100
@@ -152,7 +152,7 @@ static const uint8_t qemu_hub_config_des
 
 static const uint8_t qemu_hub_hub_descriptor[] =
 {
-       0x09,                   /*  u8  bLength; */
+       0x00,                   /*  u8  bLength; patched in later */
        0x29,                   /*  u8  bDescriptorType; Hub-descriptor */
        0x00,                   /*  u8  bNbrPorts; (patched later) */
        0x0a,                   /* u16  wHubCharacteristics; */
@@ -179,6 +179,9 @@ static void usb_hub_attach(USBPort *port
         else
             port->wPortStatus &= ~PORT_STAT_LOW_SPEED;
         port->port.dev = dev;
+        /* send the attach message */
+        dev->handle_packet(dev, 
+                           USB_MSG_ATTACH, 0, 0, NULL, 0);
     } else {
         dev = port->port.dev;
         if (dev) {
@@ -188,6 +191,9 @@ static void usb_hub_attach(USBPort *port
                 port->wPortStatus &= ~PORT_STAT_ENABLE;
                 port->wPortChange |= PORT_STAT_C_ENABLE;
             }
+            /* send the detach message */
+            dev->handle_packet(dev, 
+                               USB_MSG_DETACH, 0, 0, NULL, 0);
             port->port.dev = NULL;
         }
     }
@@ -417,6 +423,7 @@ static int usb_hub_handle_control(USBDev
             }
 
             ret = sizeof(qemu_hub_hub_descriptor) + var_hub_size;
+            data[0] = ret;
             break;
         }
     default:
@@ -516,7 +523,14 @@ static int usb_hub_handle_packet(USBDevi
     return usb_generic_handle_packet(dev, pid, devaddr, devep, data, len);
 }
 
-USBDevice *usb_hub_init(USBPort **usb_ports, int nb_ports)
+static void usb_hub_handle_destroy(USBDevice *dev)
+{
+    USBHubState *s = (USBHubState *)dev;
+
+    qemu_free(s);
+}
+
+USBDevice *usb_hub_init(int nb_ports)
 {
     USBHubState *s;
     USBHubPort *port;
@@ -534,16 +548,16 @@ USBDevice *usb_hub_init(USBPort **usb_po
     s->dev.handle_reset = usb_hub_handle_reset;
     s->dev.handle_control = usb_hub_handle_control;
     s->dev.handle_data = usb_hub_handle_data;
+    s->dev.handle_destroy = usb_hub_handle_destroy;
+
+    pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Hub");
 
     s->nb_ports = nb_ports;
     for(i = 0; i < s->nb_ports; i++) {
         port = &s->ports[i];
+        qemu_register_usb_port(&port->port, s, i, usb_hub_attach);
         port->wPortStatus = PORT_STAT_POWER;
         port->wPortChange = 0;
-        port->port.attach = usb_hub_attach;
-        port->port.opaque = s;
-        port->port.index = i;
-        usb_ports[i] = &port->port;
     }
     return (USBDevice *)s;
 }
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/usb-uhci.c
--- a/tools/ioemu/hw/usb-uhci.c Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/hw/usb-uhci.c Mon Aug 07 18:25:30 2006 +0100
@@ -327,9 +327,8 @@ static void uhci_attach(USBPort *port1, 
             usb_attach(port1, NULL);
         }
         /* set connect status */
-        if (!(port->ctrl & UHCI_PORT_CCS)) {
-            port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC;
-        }
+        port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC;
+
         /* update speed */
         if (dev->speed == USB_SPEED_LOW)
             port->ctrl |= UHCI_PORT_LSDA;
@@ -341,8 +340,9 @@ static void uhci_attach(USBPort *port1, 
                            USB_MSG_ATTACH, 0, 0, NULL, 0);
     } else {
         /* set connect status */
-        if (!(port->ctrl & UHCI_PORT_CCS)) {
-            port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC;
+        if (port->ctrl & UHCI_PORT_CCS) {
+            port->ctrl &= ~UHCI_PORT_CCS;
+            port->ctrl |= UHCI_PORT_CSC;
         }
         /* disable port */
         if (port->ctrl & UHCI_PORT_EN) {
@@ -638,17 +638,15 @@ static void uhci_map(PCIDevice *pci_dev,
     register_ioport_read(addr, 32, 1, uhci_ioport_readb, s);
 }
 
-void usb_uhci_init(PCIBus *bus, USBPort **usb_ports)
+void usb_uhci_init(PCIBus *bus, int devfn)
 {
     UHCIState *s;
     uint8_t *pci_conf;
-    UHCIPort *port;
     int i;
 
     s = (UHCIState *)pci_register_device(bus,
                                         "USB-UHCI", sizeof(UHCIState),
-                                        ((PCIDevice *)piix3_state)->devfn + 2, 
-                                        NULL, NULL);
+                                        devfn, NULL, NULL);
     pci_conf = s->dev.config;
     pci_conf[0x00] = 0x86;
     pci_conf[0x01] = 0x80;
@@ -663,11 +661,7 @@ void usb_uhci_init(PCIBus *bus, USBPort 
     pci_conf[0x60] = 0x10; // release number
     
     for(i = 0; i < NB_PORTS; i++) {
-        port = &s->ports[i];
-        port->port.opaque = s;
-        port->port.index = i;
-        port->port.attach = uhci_attach;
-        usb_ports[i] = &port->port;
+        qemu_register_usb_port(&s->ports[i].port, s, i, uhci_attach);
     }
     s->frame_timer = qemu_new_timer(vm_clock, uhci_frame_timer, s);
 
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/usb.h
--- a/tools/ioemu/hw/usb.h      Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/hw/usb.h      Mon Aug 07 18:25:30 2006 +0100
@@ -116,6 +116,8 @@ struct USBDevice {
     int (*handle_packet)(USBDevice *dev, int pid, 
                          uint8_t devaddr, uint8_t devep,
                          uint8_t *data, int len);
+    void (*handle_destroy)(USBDevice *dev);
+
     int speed;
     
     /* The following fields are used by the generic USB device
@@ -127,6 +129,7 @@ struct USBDevice {
     int (*handle_data)(USBDevice *dev, int pid, uint8_t devep,
                        uint8_t *data, int len);
     uint8_t addr;
+    char devname[32];
     
     int state;
     uint8_t setup_buf[8];
@@ -137,12 +140,15 @@ struct USBDevice {
     int setup_index;
 };
 
+typedef void (*usb_attachfn)(USBPort *port, USBDevice *dev);
+
 /* USB port on which a device can be connected */
 struct USBPort {
     USBDevice *dev;
-    void (*attach)(USBPort *port, USBDevice *dev);
+    usb_attachfn attach;
     void *opaque;
     int index; /* internal port index, may be used with the opaque */
+    struct USBPort *next; /* Used internally by qemu.  */
 };
 
 void usb_attach(USBPort *port, USBDevice *dev);
@@ -152,10 +158,13 @@ int set_usb_string(uint8_t *buf, const c
 int set_usb_string(uint8_t *buf, const char *str);
 
 /* usb hub */
-USBDevice *usb_hub_init(USBPort **usb_ports, int nb_ports);
+USBDevice *usb_hub_init(int nb_ports);
 
 /* usb-uhci.c */
-void usb_uhci_init(PCIBus *bus, USBPort **usb_ports);
+void usb_uhci_init(PCIBus *bus, int devfn);
+
+/* usb-ohci.c */
+void usb_ohci_init(struct PCIBus *bus, int num_ports, int devfn);
 
 /* usb-linux.c */
 USBDevice *usb_host_device_open(const char *devname);
@@ -164,3 +173,6 @@ void usb_host_info(void);
 /* usb-hid.c */
 USBDevice *usb_mouse_init(void);
 USBDevice *usb_tablet_init(void);
+
+/* usb-msd.c */
+USBDevice *usb_msd_init(const char *filename);
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/versatilepb.c
--- a/tools/ioemu/hw/versatilepb.c      Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/hw/versatilepb.c      Mon Aug 07 18:25:30 2006 +0100
@@ -9,6 +9,8 @@
 
 #include "vl.h"
 #include "arm_pic.h"
+
+#define LOCK_VALUE 0xa05f
 
 /* Primary interrupt controller.  */
 
@@ -145,6 +147,188 @@ static vpb_sic_state *vpb_sic_init(uint3
     return s;
 }
 
+/* System controller.  */
+
+typedef struct {
+    uint32_t base;
+    uint32_t leds;
+    uint16_t lockval;
+    uint32_t cfgdata1;
+    uint32_t cfgdata2;
+    uint32_t flags;
+    uint32_t nvflags;
+    uint32_t resetlevel;
+} vpb_sys_state;
+
+static uint32_t vpb_sys_read(void *opaque, target_phys_addr_t offset)
+{
+    vpb_sys_state *s = (vpb_sys_state *)opaque;
+
+    offset -= s->base;
+    switch (offset) {
+    case 0x00: /* ID */
+        return 0x41007004;
+    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 */
+        return s->resetlevel;
+    case 0x44: /* PCICTL */
+        return 1;
+    case 0x48: /* MCI */
+        return 0;
+    case 0x4c: /* FLASH */
+        return 0;
+    case 0x50: /* CLCD */
+        return 0x1000;
+    case 0x54: /* CLCDSER */
+        return 0;
+    case 0x58: /* BOOTCS */
+        return 0;
+    case 0x5c: /* 24MHz */
+        /* ??? not implemented.  */
+        return 0;
+    case 0x60: /* MISC */
+        return 0;
+    case 0x64: /* DMAPSR0 */
+    case 0x68: /* DMAPSR1 */
+    case 0x6c: /* DMAPSR2 */
+    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;
+    default:
+        printf ("vpb_sys_read: Bad register offset 0x%x\n", offset);
+        return 0;
+    }
+}
+
+static void vpb_sys_write(void *opaque, target_phys_addr_t offset,
+                          uint32_t val)
+{
+    vpb_sys_state *s = (vpb_sys_state *)opaque;
+    offset -= s->base;
+
+    switch (offset) {
+    case 0x08: /* LED */
+        s->leds = val;
+    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 */
+        if (s->lockval == LOCK_VALUE) {
+            s->resetlevel = val;
+            if (val & 0x100)
+                cpu_abort(cpu_single_env, "Board reset\n");
+        }
+        break;
+    case 0x44: /* PCICTL */
+        /* nothing to do.  */
+        break;
+    case 0x4c: /* FLASH */
+    case 0x50: /* CLCD */
+    case 0x54: /* CLCDSER */
+    case 0x64: /* DMAPSR0 */
+    case 0x68: /* DMAPSR1 */
+    case 0x6c: /* DMAPSR2 */
+    case 0x8c: /* OSCRESET0 */
+    case 0x90: /* OSCRESET1 */
+    case 0x94: /* OSCRESET2 */
+    case 0x98: /* OSCRESET3 */
+    case 0x9c: /* OSCRESET4 */
+        break;
+    default:
+        printf ("vpb_sys_write: Bad register offset 0x%x\n", offset);
+        return;
+    }
+}
+
+static CPUReadMemoryFunc *vpb_sys_readfn[] = {
+   vpb_sys_read,
+   vpb_sys_read,
+   vpb_sys_read
+};
+
+static CPUWriteMemoryFunc *vpb_sys_writefn[] = {
+   vpb_sys_write,
+   vpb_sys_write,
+   vpb_sys_write
+};
+
+static vpb_sys_state *vpb_sys_init(uint32_t base)
+{
+    vpb_sys_state *s;
+    int iomemtype;
+
+    s = (vpb_sys_state *)qemu_mallocz(sizeof(vpb_sys_state));
+    if (!s)
+        return NULL;
+    s->base = base;
+    iomemtype = cpu_register_io_memory(0, vpb_sys_readfn,
+                                       vpb_sys_writefn, s);
+    cpu_register_physical_memory(base, 0x00000fff, iomemtype);
+    /* ??? Save/restore.  */
+    return s;
+}
+
 /* Board init.  */
 
 /* The AB and PB boards both use the same core, just with different
@@ -159,6 +343,11 @@ static void versatile_init(int ram_size,
     CPUState *env;
     void *pic;
     void *sic;
+    void *scsi_hba;
+    PCIBus *pci_bus;
+    NICInfo *nd;
+    int n;
+    int done_smc = 0;
 
     env = cpu_init();
     cpu_arm_set_model(env, ARM_CPUID_ARM926);
@@ -166,20 +355,33 @@ static void versatile_init(int ram_size,
     /* SDRAM at address zero.  */
     cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
 
+    vpb_sys_init(0x10000000);
     pic = arm_pic_init_cpu(env);
     pic = pl190_init(0x10140000, pic, ARM_PIC_CPU_IRQ, ARM_PIC_CPU_FIQ);
     sic = vpb_sic_init(0x10003000, pic, 31);
     pl050_init(0x10006000, sic, 3, 0);
     pl050_init(0x10007000, sic, 4, 1);
 
-    /* TODO: Init PCI NICs.  */
-    if (nd_table[0].vlan) {
-        if (nd_table[0].model == NULL
-            || strcmp(nd_table[0].model, "smc91c111") == 0) {
-            smc91c111_init(&nd_table[0], 0x10010000, sic, 25);
+    pci_bus = pci_vpb_init(sic);
+    /* The Versatile PCI bridge does not provide access to PCI IO space,
+       so many of the qemu PCI devices are not useable.  */
+    for(n = 0; n < nb_nics; n++) {
+        nd = &nd_table[n];
+        if (!nd->model)
+            nd->model = done_smc ? "rtl8139" : "smc91c111";
+        if (strcmp(nd->model, "smc91c111") == 0) {
+            smc91c111_init(nd, 0x10010000, sic, 25);
         } else {
-            fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
-            exit (1);
+            pci_nic_init(pci_bus, nd);
+        }
+    }
+    if (usb_enabled) {
+        usb_ohci_init(pci_bus, 3, -1);
+    }
+    scsi_hba = lsi_scsi_init(pci_bus, -1);
+    for (n = 0; n < MAX_DISKS; n++) {
+        if (bs_table[n]) {
+            lsi_scsi_attach(scsi_hba, bs_table[n], n);
         }
     }
 
diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/vga.c
--- a/tools/ioemu/hw/vga.c      Mon Aug 07 18:11:59 2006 +0100
+++ b/tools/ioemu/hw/vga.c      Mon Aug 07 18:25:30 2006 +0100
@@ -378,10 +378,29 @@ static uint32_t vbe_ioport_read_data(voi
     VGAState *s = opaque;
     uint32_t val;
 
-    if (s->vbe_index <= VBE_DISPI_INDEX_NB)
-        val = s->vbe_regs[s->vbe_index];
-    else
+    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 {
         val = 0;
+    }
 #ifdef DEBUG_BOCHS_VBE
     printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
 #endif
@@ -434,7 +453,8 @@ static void vbe_ioport_write_data(void *
             s->bank_offset = (val << 16);
             break;
         case VBE_DISPI_INDEX_ENABLE:
-            if (val & VBE_DISPI_ENABLED) {
+            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] = 
@@ -450,7 +470,7 @@ static void vbe_ioport_write_data(void *
                     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, 
@@ -464,7 +484,7 @@ static void vbe_ioport_write_data(void *
                 s->cr[0x13] = s->vbe_line_offset >> 3;
                 /* width */
                 s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
-                /* height */
+                /* height (only meaningful if < 1024) */
                 h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
                 s->cr[0x12] = h;
                 s->cr[0x07] = (s->cr[0x07] & ~0x42) | 
@@ -808,6 +828,11 @@ static inline unsigned int rgb_to_pixel3
     return (r << 16) | (g << 8) | b;
 }
 
+static inline unsigned int rgb_to_pixel32bgr(unsigned int r, unsigned int g, 
unsigned b)
+{
+    return (b << 16) | (g << 8) | r;
+}
+
 #define DEPTH 8
 #include "vga_template.h"
 
@@ -817,6 +842,10 @@ static inline unsigned int rgb_to_pixel3
 #define DEPTH 16
 #include "vga_template.h"
 
+#define DEPTH 32
+#include "vga_template.h"
+
+#define BGR_FORMAT
 #define DEPTH 32
 #include "vga_template.h"
 
@@ -849,6 +878,13 @@ static unsigned int rgb_to_pixel32_dup(u
 {
     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;
 }
 
@@ -948,9 +984,11 @@ static int update_basic_params(VGAState 
     return full_update;
 }
 
-static inline int get_depth_index(int depth)
-{
-    switch(depth) {
+#define NB_DEPTHS 5
+
+static inline int get_depth_index(DisplayState *s)
+{
+    switch(s->depth) {
     default:
     case 8:
         return 0;
@@ -959,28 +997,34 @@ static inline int get_depth_index(int de
     case 16:
         return 2;
     case 32:
-        return 3;
-    }
-}
-
-static vga_draw_glyph8_func *vga_draw_glyph8_table[4] = {
+        if (s->bgr)
+            return 4;
+        else
+            return 3;
+    }
+}
+
+static vga_draw_glyph8_func *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,
 };
 
-static vga_draw_glyph8_func *vga_draw_glyph16_table[4] = {
+static vga_draw_glyph8_func *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,
 };
 
-static vga_draw_glyph9_func *vga_draw_glyph9_table[4] = {
+static vga_draw_glyph9_func *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,
 };
     
@@ -1103,7 +1147,7 @@ static void vga_draw_text(VGAState *s, i
     }
     cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
     
-    depth_index = get_depth_index(s->ds->depth);
+    depth_index = get_depth_index(s->ds);
     if (cw == 16)
         vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
     else
@@ -1196,56 +1240,76 @@ enum {
     VGA_DRAW_LINE_NB,
 };
 
-static vga_draw_line_func *vga_draw_line_table[4 * VGA_DRAW_LINE_NB] = {
+static vga_draw_line_func *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_line2d2_8,
     vga_draw_line2d2_16,
     vga_draw_line2d2_16,
     vga_draw_line2d2_32,
+    vga_draw_line2d2_32,
 
     vga_draw_line4_8,
     vga_draw_line4_16,
     vga_draw_line4_16,
     vga_draw_line4_32,
+    vga_draw_line4_32,
 
     vga_draw_line4d2_8,

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog

<Prev in Thread] Current Thread [Next in Thread>