r3832 - in trunk/src/host/qemu-neo1973: . audio hw linux-user target-cris target-mips

andrew at sita.openmoko.org andrew at sita.openmoko.org
Tue Jan 15 00:24:35 CET 2008


Author: andrew
Date: 2008-01-15 00:24:21 +0100 (Tue, 15 Jan 2008)
New Revision: 3832

Added:
   trunk/src/host/qemu-neo1973/audio/audio_pt_int.c
   trunk/src/host/qemu-neo1973/audio/audio_pt_int.h
   trunk/src/host/qemu-neo1973/audio/esdaudio.c
   trunk/src/host/qemu-neo1973/hw/ac97.c
   trunk/src/host/qemu-neo1973/hw/gus.c
   trunk/src/host/qemu-neo1973/hw/gusemu.h
   trunk/src/host/qemu-neo1973/hw/gusemu_hal.c
   trunk/src/host/qemu-neo1973/hw/gusemu_mixer.c
   trunk/src/host/qemu-neo1973/hw/gustate.h
   trunk/src/host/qemu-neo1973/hw/usb-serial.c
Modified:
   trunk/src/host/qemu-neo1973/Makefile
   trunk/src/host/qemu-neo1973/Makefile.target
   trunk/src/host/qemu-neo1973/audio/alsaaudio.c
   trunk/src/host/qemu-neo1973/audio/audio.c
   trunk/src/host/qemu-neo1973/audio/audio_int.h
   trunk/src/host/qemu-neo1973/audio/dsound_template.h
   trunk/src/host/qemu-neo1973/audio/dsoundaudio.c
   trunk/src/host/qemu-neo1973/audio/ossaudio.c
   trunk/src/host/qemu-neo1973/audio/wavaudio.c
   trunk/src/host/qemu-neo1973/block-vmdk.c
   trunk/src/host/qemu-neo1973/configure
   trunk/src/host/qemu-neo1973/hw/acpi.c
   trunk/src/host/qemu-neo1973/hw/audiodev.h
   trunk/src/host/qemu-neo1973/hw/dma.c
   trunk/src/host/qemu-neo1973/hw/ide.c
   trunk/src/host/qemu-neo1973/hw/sb16.c
   trunk/src/host/qemu-neo1973/hw/usb-hid.c
   trunk/src/host/qemu-neo1973/hw/usb.h
   trunk/src/host/qemu-neo1973/hw/vmware_vga.c
   trunk/src/host/qemu-neo1973/linux-user/main.c
   trunk/src/host/qemu-neo1973/qemu-doc.texi
   trunk/src/host/qemu-neo1973/target-cris/op.c
   trunk/src/host/qemu-neo1973/target-cris/translate.c
   trunk/src/host/qemu-neo1973/target-mips/exec.h
   trunk/src/host/qemu-neo1973/target-mips/op_helper.c
   trunk/src/host/qemu-neo1973/vl.c
   trunk/src/host/qemu-neo1973/vnc.c
Log:
Pull changes from upstream.


Modified: trunk/src/host/qemu-neo1973/Makefile
===================================================================
--- trunk/src/host/qemu-neo1973/Makefile	2008-01-14 20:40:58 UTC (rev 3831)
+++ trunk/src/host/qemu-neo1973/Makefile	2008-01-14 23:24:21 UTC (rev 3832)
@@ -59,7 +59,7 @@
 OBJS+=scsi-disk.o cdrom.o
 OBJS+=scsi-generic.o
 OBJS+=usb.o usb-hub.o usb-linux.o usb-linux-gadget.o
-OBJS+=usb-hid.o usb-msd.o usb-wacom.o usb-net.o usb-bt.o
+OBJS+=usb-hid.o usb-msd.o usb-wacom.o usb-net.o usb-bt.o usb-serial.o
 OBJS+=sd.o ssi-sd.o ar6000.o
 
 ifdef CONFIG_WIN32
@@ -75,6 +75,7 @@
 endif
 ifdef CONFIG_COREAUDIO
 AUDIO_OBJS += coreaudio.o
+AUDIO_PT = yes
 endif
 ifdef CONFIG_ALSA
 AUDIO_OBJS += alsaaudio.o
@@ -86,6 +87,17 @@
 AUDIO_OBJS += fmodaudio.o
 audio/audio.o audio/fmodaudio.o: CPPFLAGS := -I$(CONFIG_FMOD_INC) $(CPPFLAGS)
 endif
+ifdef CONFIG_ESD
+AUDIO_PT = yes
+AUDIO_PT_INT = yes
+AUDIO_OBJS += esdaudio.o
+endif
+ifdef AUDIO_PT
+LDFLAGS += -pthread
+endif
+ifdef AUDIO_PT_INT
+AUDIO_OBJS += audio_pt_int.o
+endif
 AUDIO_OBJS+= wavcapture.o
 OBJS+=$(addprefix audio/, $(AUDIO_OBJS))
 
@@ -159,6 +171,7 @@
 # avoid old build problems by removing potentially incorrect old files
 	rm -f config.mak config.h op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
 	rm -f *.o *.d *.a $(TOOLS) dyngen$(EXESUF) TAGS cscope.* *.pod *~ */*~
+	rm -rf dyngen.dSYM
 	rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d
 	$(MAKE) -C tests clean
 	for d in $(TARGET_DIRS); do \

Modified: trunk/src/host/qemu-neo1973/Makefile.target
===================================================================
--- trunk/src/host/qemu-neo1973/Makefile.target	2008-01-14 20:40:58 UTC (rev 3831)
+++ trunk/src/host/qemu-neo1973/Makefile.target	2008-01-14 23:24:21 UTC (rev 3832)
@@ -404,6 +404,9 @@
 ifdef CONFIG_ALSA
 LIBS += -lasound
 endif
+ifdef CONFIG_ESD
+LIBS += -lesd
+endif
 ifdef CONFIG_DSOUND
 LIBS += -lole32 -ldxguid
 endif
@@ -412,9 +415,15 @@
 endif
 
 SOUND_HW = sb16.o es1370.o
+ifdef CONFIG_AC97
+SOUND_HW += ac97.o
+endif
 ifdef CONFIG_ADLIB
 SOUND_HW += fmopl.o adlib.o
 endif
+ifdef CONFIG_GUS
+SOUND_HW += gus.o gusemu_hal.o gusemu_mixer.o
+endif
 
 ifdef CONFIG_VNC_TLS
 CPPFLAGS += $(CONFIG_VNC_TLS_CFLAGS)
@@ -652,8 +661,9 @@
 
 ifeq (1, 0)
 audio.o sdlaudio.o dsoundaudio.o ossaudio.o wavaudio.o noaudio.o \
-fmodaudio.o alsaaudio.o mixeng.o sb16.o es1370.o gus.o adlib.o: \
-CFLAGS := $(CFLAGS) -Wall -Werror -W -Wsign-compare
+fmodaudio.o alsaaudio.o mixeng.o sb16.o es1370.o ac97.o gus.o adlib.o \
+esdaudio.o audio_pt_int.o: \
+CFLAGS := $(CFLAGS) -O0 -g -Wall -Werror -W -Wsign-compare -Wno-unused
 endif
 
 # Include automatically generated dependency files

Modified: trunk/src/host/qemu-neo1973/audio/alsaaudio.c
===================================================================
--- trunk/src/host/qemu-neo1973/audio/alsaaudio.c	2008-01-14 20:40:58 UTC (rev 3831)
+++ trunk/src/host/qemu-neo1973/audio/alsaaudio.c	2008-01-14 23:24:21 UTC (rev 3832)
@@ -86,9 +86,9 @@
 };
 
 struct alsa_params_req {
-    unsigned int freq;
-    audfmt_e fmt;
-    unsigned int nchannels;
+    int freq;
+    snd_pcm_format_t fmt;
+    int nchannels;
     unsigned int buffer_size;
     unsigned int period_size;
 };
@@ -96,6 +96,7 @@
 struct alsa_params_obt {
     int freq;
     audfmt_e fmt;
+    int endianness;
     int nchannels;
     snd_pcm_uframes_t samples;
 };
@@ -143,7 +144,7 @@
     return audio_pcm_sw_write (sw, buf, len);
 }
 
-static int aud_to_alsafmt (audfmt_e fmt)
+static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt)
 {
     switch (fmt) {
     case AUD_FMT_S8:
@@ -173,7 +174,8 @@
     }
 }
 
-static int alsa_to_audfmt (int alsafmt, audfmt_e *fmt, int *endianness)
+static int alsa_to_audfmt (snd_pcm_format_t alsafmt, audfmt_e *fmt,
+                           int *endianness)
 {
     switch (alsafmt) {
     case SND_PCM_FORMAT_S8:
@@ -234,7 +236,6 @@
     return 0;
 }
 
-#if defined DEBUG_MISMATCHES || defined DEBUG
 static void alsa_dump_info (struct alsa_params_req *req,
                             struct alsa_params_obt *obt)
 {
@@ -248,7 +249,6 @@
            req->buffer_size, req->period_size);
     dolog ("obtained: samples %ld\n", obt->samples);
 }
-#endif
 
 static void alsa_set_threshold (snd_pcm_t *handle, snd_pcm_uframes_t threshold)
 {
@@ -291,6 +291,7 @@
     unsigned int period_size, buffer_size;
     snd_pcm_uframes_t obt_buffer_size;
     const char *typ = in ? "ADC" : "DAC";
+    snd_pcm_format_t obtfmt;
 
     freq = req->freq;
     period_size = req->period_size;
@@ -327,9 +328,8 @@
     }
 
     err = snd_pcm_hw_params_set_format (handle, hw_params, req->fmt);
-    if (err < 0) {
+    if (err < 0 && conf.verbose) {
         alsa_logerr2 (err, typ, "Failed to set format %d\n", req->fmt);
-        goto err;
     }
 
     err = snd_pcm_hw_params_set_rate_near (handle, hw_params, &freq, 0);
@@ -494,6 +494,17 @@
         goto err;
     }
 
+    err = snd_pcm_hw_params_get_format (hw_params, &obtfmt);
+    if (err < 0) {
+        alsa_logerr2 (err, typ, "Failed to get format\n");
+        goto err;
+    }
+
+    if (alsa_to_audfmt (obtfmt, &obt->fmt, &obt->endianness)) {
+        dolog ("Invalid format was returned %d\n", obtfmt);
+        goto err;
+    }
+
     err = snd_pcm_prepare (handle);
     if (err < 0) {
         alsa_logerr2 (err, typ, "Could not prepare handle %p\n", handle);
@@ -504,28 +515,41 @@
         snd_pcm_uframes_t threshold;
         int bytes_per_sec;
 
-        bytes_per_sec = freq
-            << (nchannels == 2)
-            << (req->fmt == AUD_FMT_S16 || req->fmt == AUD_FMT_U16);
+        bytes_per_sec = freq << (nchannels == 2);
 
+        switch (obt->fmt) {
+        case AUD_FMT_S8:
+        case AUD_FMT_U8:
+            break;
+
+        case AUD_FMT_S16:
+        case AUD_FMT_U16:
+            bytes_per_sec <<= 1;
+            break;
+
+        case AUD_FMT_S32:
+        case AUD_FMT_U32:
+            bytes_per_sec <<= 2;
+            break;
+        }
+
         threshold = (conf.threshold * bytes_per_sec) / 1000;
         alsa_set_threshold (handle, threshold);
     }
 
-    obt->fmt = req->fmt;
     obt->nchannels = nchannels;
     obt->freq = freq;
     obt->samples = obt_buffer_size;
+
     *handlep = handle;
 
-#if defined DEBUG_MISMATCHES || defined DEBUG
-    if (obt->fmt != req->fmt ||
-        obt->nchannels != req->nchannels ||
-        obt->freq != req->freq) {
-        dolog ("Audio paramters mismatch for %s\n", typ);
+    if (conf.verbose &&
+        (obt->fmt != req->fmt ||
+         obt->nchannels != req->nchannels ||
+         obt->freq != req->freq)) {
+        dolog ("Audio paramters for %s\n", typ);
         alsa_dump_info (req, obt);
     }
-#endif
 
 #ifdef DEBUG
     alsa_dump_info (req, obt);
@@ -665,9 +689,6 @@
     ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
     struct alsa_params_req req;
     struct alsa_params_obt obt;
-    audfmt_e effective_fmt;
-    int endianness;
-    int err;
     snd_pcm_t *handle;
     audsettings_t obt_as;
 
@@ -681,16 +702,10 @@
         return -1;
     }
 
-    err = alsa_to_audfmt (obt.fmt, &effective_fmt, &endianness);
-    if (err) {
-        alsa_anal_close (&handle);
-        return -1;
-    }
-
     obt_as.freq = obt.freq;
     obt_as.nchannels = obt.nchannels;
-    obt_as.fmt = effective_fmt;
-    obt_as.endianness = endianness;
+    obt_as.fmt = obt.fmt;
+    obt_as.endianness = obt.endianness;
 
     audio_pcm_init_info (&hw->info, &obt_as);
     hw->samples = obt.samples;
@@ -751,9 +766,6 @@
     ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
     struct alsa_params_req req;
     struct alsa_params_obt obt;
-    int endianness;
-    int err;
-    audfmt_e effective_fmt;
     snd_pcm_t *handle;
     audsettings_t obt_as;
 
@@ -767,16 +779,10 @@
         return -1;
     }
 
-    err = alsa_to_audfmt (obt.fmt, &effective_fmt, &endianness);
-    if (err) {
-        alsa_anal_close (&handle);
-        return -1;
-    }
-
     obt_as.freq = obt.freq;
     obt_as.nchannels = obt.nchannels;
-    obt_as.fmt = effective_fmt;
-    obt_as.endianness = endianness;
+    obt_as.fmt = obt.fmt;
+    obt_as.endianness = obt.endianness;
 
     audio_pcm_init_info (&hw->info, &obt_as);
     hw->samples = obt.samples;

Modified: trunk/src/host/qemu-neo1973/audio/audio.c
===================================================================
--- trunk/src/host/qemu-neo1973/audio/audio.c	2008-01-14 20:40:58 UTC (rev 3831)
+++ trunk/src/host/qemu-neo1973/audio/audio.c	2008-01-14 23:24:21 UTC (rev 3832)
@@ -56,6 +56,9 @@
 #ifdef CONFIG_SDL
     &sdl_audio_driver,
 #endif
+#ifdef CONFIG_ESD
+    &esd_audio_driver,
+#endif
     &no_audio_driver,
     &wav_audio_driver
 };
@@ -414,7 +417,7 @@
             {
                 audfmt_e *fmtp = opt->valp;
                 printf (
-                    "format, %s = %s, (one of: U8 S8 U16 S16)\n",
+                    "format, %s = %s, (one of: U8 S8 U16 S16 U32 S32)\n",
                     state,
                     audio_audfmt_to_string (*fmtp)
                     );

Modified: trunk/src/host/qemu-neo1973/audio/audio_int.h
===================================================================
--- trunk/src/host/qemu-neo1973/audio/audio_int.h	2008-01-14 20:40:58 UTC (rev 3831)
+++ trunk/src/host/qemu-neo1973/audio/audio_int.h	2008-01-14 23:24:21 UTC (rev 3832)
@@ -202,6 +202,7 @@
 extern struct audio_driver alsa_audio_driver;
 extern struct audio_driver coreaudio_audio_driver;
 extern struct audio_driver dsound_audio_driver;
+extern struct audio_driver esd_audio_driver;
 extern volume_t nominal_volume;
 
 void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as);

Added: trunk/src/host/qemu-neo1973/audio/audio_pt_int.c
===================================================================
--- trunk/src/host/qemu-neo1973/audio/audio_pt_int.c	2008-01-14 20:40:58 UTC (rev 3831)
+++ trunk/src/host/qemu-neo1973/audio/audio_pt_int.c	2008-01-14 23:24:21 UTC (rev 3832)
@@ -0,0 +1,149 @@
+#include "qemu-common.h"
+#include "audio.h"
+
+#define AUDIO_CAP "audio-pt"
+
+#include "audio_int.h"
+#include "audio_pt_int.h"
+
+static void logerr (struct audio_pt *pt, int err, const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start (ap, fmt);
+    AUD_vlog (pt->drv, fmt, ap);
+    va_end (ap);
+
+    AUD_log (NULL, "\n");
+    AUD_log (pt->drv, "Reason: %s\n", strerror (err));
+}
+
+int audio_pt_init (struct audio_pt *p, void *(*func) (void *),
+                   void *opaque, const char *drv, const char *cap)
+{
+    int err, err2;
+    const char *efunc;
+
+    p->drv = drv;
+
+    err = pthread_mutex_init (&p->mutex, NULL);
+    if (err) {
+        efunc = "pthread_mutex_init";
+        goto err0;
+    }
+
+    err = pthread_cond_init (&p->cond, NULL);
+    if (err) {
+        efunc = "pthread_cond_init";
+        goto err1;
+    }
+
+    err = pthread_create (&p->thread, NULL, func, opaque);
+    if (err) {
+        efunc = "pthread_create";
+        goto err2;
+    }
+
+    return 0;
+
+ err2:
+    err2 = pthread_cond_destroy (&p->cond);
+    if (err2) {
+        logerr (p, err2, "%s(%s): pthread_cond_destroy failed", cap, AUDIO_FUNC);
+    }
+
+ err1:
+    err2 = pthread_mutex_destroy (&p->mutex);
+    if (err2) {
+        logerr (p, err2, "%s(%s): pthread_mutex_destroy failed", cap, AUDIO_FUNC);
+    }
+
+ err0:
+    logerr (p, err, "%s(%s): %s failed", cap, AUDIO_FUNC, efunc);
+    return -1;
+}
+
+int audio_pt_fini (struct audio_pt *p, const char *cap)
+{
+    int err, ret = 0;
+
+    err = pthread_cond_destroy (&p->cond);
+    if (err) {
+        logerr (p, err, "%s(%s): pthread_cond_destroy failed", cap, AUDIO_FUNC);
+        ret = -1;
+    }
+
+    err = pthread_mutex_destroy (&p->mutex);
+    if (err) {
+        logerr (p, err, "%s(%s): pthread_mutex_destroy failed", cap, AUDIO_FUNC);
+        ret = -1;
+    }
+    return ret;
+}
+
+int audio_pt_lock (struct audio_pt *p, const char *cap)
+{
+    int err;
+
+    err = pthread_mutex_lock (&p->mutex);
+    if (err) {
+        logerr (p, err, "%s(%s): pthread_mutex_lock failed", cap, AUDIO_FUNC);
+        return -1;
+    }
+    return 0;
+}
+
+int audio_pt_unlock (struct audio_pt *p, const char *cap)
+{
+    int err;
+
+    err = pthread_mutex_unlock (&p->mutex);
+    if (err) {
+        logerr (p, err, "%s(%s): pthread_mutex_unlock failed", cap, AUDIO_FUNC);
+        return -1;
+    }
+    return 0;
+}
+
+int audio_pt_wait (struct audio_pt *p, const char *cap)
+{
+    int err;
+
+    err = pthread_cond_wait (&p->cond, &p->mutex);
+    if (err) {
+        logerr (p, err, "%s(%s): pthread_cond_wait failed", cap, AUDIO_FUNC);
+        return -1;
+    }
+    return 0;
+}
+
+int audio_pt_unlock_and_signal (struct audio_pt *p, const char *cap)
+{
+    int err;
+
+    err = pthread_mutex_unlock (&p->mutex);
+    if (err) {
+        logerr (p, err, "%s(%s): pthread_mutex_unlock failed", cap, AUDIO_FUNC);
+        return -1;
+    }
+    err = pthread_cond_signal (&p->cond);
+    if (err) {
+        logerr (p, err, "%s(%s): pthread_cond_signal failed", cap, AUDIO_FUNC);
+        return -1;
+    }
+    return 0;
+}
+
+int audio_pt_join (struct audio_pt *p, void **arg, const char *cap)
+{
+    int err;
+    void *ret;
+
+    err = pthread_join (p->thread, &ret);
+    if (err) {
+        logerr (p, err, "%s(%s): pthread_join failed", cap, AUDIO_FUNC);
+        return -1;
+    }
+    *arg = ret;
+    return 0;
+}

Added: trunk/src/host/qemu-neo1973/audio/audio_pt_int.h
===================================================================
--- trunk/src/host/qemu-neo1973/audio/audio_pt_int.h	2008-01-14 20:40:58 UTC (rev 3831)
+++ trunk/src/host/qemu-neo1973/audio/audio_pt_int.h	2008-01-14 23:24:21 UTC (rev 3832)
@@ -0,0 +1,22 @@
+#ifndef QEMU_AUDIO_PT_INT_H
+#define QEMU_AUDIO_PT_INT_H
+
+#include <pthread.h>
+
+struct audio_pt {
+    const char *drv;
+    pthread_t thread;
+    pthread_cond_t cond;
+    pthread_mutex_t mutex;
+};
+
+int audio_pt_init (struct audio_pt *, void *(*) (void *), void *,
+                   const char *, const char *);
+int audio_pt_fini (struct audio_pt *, const char *);
+int audio_pt_lock (struct audio_pt *, const char *);
+int audio_pt_unlock (struct audio_pt *, const char *);
+int audio_pt_wait (struct audio_pt *, const char *);
+int audio_pt_unlock_and_signal (struct audio_pt *, const char *);
+int audio_pt_join (struct audio_pt *, void **, const char *);
+
+#endif /* audio_pt_int.h */

Modified: trunk/src/host/qemu-neo1973/audio/dsound_template.h
===================================================================
--- trunk/src/host/qemu-neo1973/audio/dsound_template.h	2008-01-14 20:40:58 UTC (rev 3831)
+++ trunk/src/host/qemu-neo1973/audio/dsound_template.h	2008-01-14 23:24:21 UTC (rev 3832)
@@ -23,16 +23,20 @@
  */
 #ifdef DSBTYPE_IN
 #define NAME "capture buffer"
+#define NAME2 "DirectSoundCapture"
 #define TYPE in
 #define IFACE IDirectSoundCaptureBuffer
 #define BUFPTR LPDIRECTSOUNDCAPTUREBUFFER
 #define FIELD dsound_capture_buffer
+#define FIELD2 dsound_capture
 #else
 #define NAME "playback buffer"
+#define NAME2 "DirectSound"
 #define TYPE out
 #define IFACE IDirectSoundBuffer
 #define BUFPTR LPDIRECTSOUNDBUFFER
 #define FIELD dsound_buffer
+#define FIELD2 dsound
 #endif
 
 static int glue (dsound_unlock_, TYPE) (
@@ -192,6 +196,11 @@
     DSBCAPS bc;
 #endif
 
+    if (!s->FIELD2) {
+        dolog ("Attempt to initialize voice without " NAME2 " object");
+        return -1;
+    }
+
     err = waveformat_from_audio_settings (&wfx, as);
     if (err) {
         return -1;

Modified: trunk/src/host/qemu-neo1973/audio/dsoundaudio.c
===================================================================
--- trunk/src/host/qemu-neo1973/audio/dsoundaudio.c	2008-01-14 20:40:58 UTC (rev 3831)
+++ trunk/src/host/qemu-neo1973/audio/dsoundaudio.c	2008-01-14 23:24:21 UTC (rev 3832)
@@ -320,23 +320,22 @@
 
     switch (as->fmt) {
     case AUD_FMT_S8:
-        wfx->wBitsPerSample = 8;
-        break;
-
     case AUD_FMT_U8:
         wfx->wBitsPerSample = 8;
         break;
 
     case AUD_FMT_S16:
+    case AUD_FMT_U16:
         wfx->wBitsPerSample = 16;
         wfx->nAvgBytesPerSec <<= 1;
         wfx->nBlockAlign <<= 1;
         break;
 
-    case AUD_FMT_U16:
-        wfx->wBitsPerSample = 16;
-        wfx->nAvgBytesPerSec <<= 1;
-        wfx->nBlockAlign <<= 1;
+    case AUD_FMT_S32:
+    case AUD_FMT_U32:
+        wfx->wBitsPerSample = 32;
+        wfx->nAvgBytesPerSec <<= 2;
+        wfx->nBlockAlign <<= 2;
         break;
 
     default:
@@ -387,8 +386,13 @@
         as->fmt = AUD_FMT_S16;
         break;
 
+    case 32:
+        as->fmt = AUD_FMT_S32;
+        break;
+
     default:
-        dolog ("Invalid wave format, bits per sample is not 8 or 16, but %d\n",
+        dolog ("Invalid wave format, bits per sample is not "
+               "8, 16 or 32, but %d\n",
                wfx->wBitsPerSample);
         return -1;
     }

Added: trunk/src/host/qemu-neo1973/audio/esdaudio.c
===================================================================
--- trunk/src/host/qemu-neo1973/audio/esdaudio.c	2008-01-14 20:40:58 UTC (rev 3831)
+++ trunk/src/host/qemu-neo1973/audio/esdaudio.c	2008-01-14 23:24:21 UTC (rev 3832)
@@ -0,0 +1,591 @@
+/*
+ * QEMU ESD audio driver
+ *
+ * Copyright (c) 2006 Frederick Reeve (brushed up by malc)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include <esd.h>
+#include "qemu-common.h"
+#include "audio.h"
+#include <signal.h>
+
+#define AUDIO_CAP "esd"
+#include "audio_int.h"
+#include "audio_pt_int.h"
+
+typedef struct {
+    HWVoiceOut hw;
+    int done;
+    int live;
+    int decr;
+    int rpos;
+    void *pcm_buf;
+    int fd;
+    struct audio_pt pt;
+} ESDVoiceOut;
+
+typedef struct {
+    HWVoiceIn hw;
+    int done;
+    int dead;
+    int incr;
+    int wpos;
+    void *pcm_buf;
+    int fd;
+    struct audio_pt pt;
+} ESDVoiceIn;
+
+static struct {
+    int samples;
+    int divisor;
+    char *dac_host;
+    char *adc_host;
+} conf = {
+    1024,
+    2,
+    NULL,
+    NULL
+};
+
+static void GCC_FMT_ATTR (2, 3) qesd_logerr (int err, const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start (ap, fmt);
+    AUD_vlog (AUDIO_CAP, fmt, ap);
+    va_end (ap);
+
+    AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
+}
+
+/* playback */
+static void *qesd_thread_out (void *arg)
+{
+    ESDVoiceOut *esd = arg;
+    HWVoiceOut *hw = &esd->hw;
+    int threshold;
+
+    threshold = conf.divisor ? hw->samples / conf.divisor : 0;
+
+    for (;;) {
+        int decr, to_mix, rpos;
+
+        for (;;) {
+            if (esd->done) {
+                goto exit;
+            }
+
+            if (esd->live > threshold) {
+                break;
+            }
+
+            if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) {
+                goto exit;
+            }
+        }
+
+        decr = to_mix = esd->live;
+        rpos = hw->rpos;
+
+        if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) {
+            return NULL;
+        }
+
+        while (to_mix) {
+            ssize_t written;
+            int chunk = audio_MIN (to_mix, hw->samples - rpos);
+            st_sample_t *src = hw->mix_buf + rpos;
+
+            hw->clip (esd->pcm_buf, src, chunk);
+
+        again:
+            written = write (esd->fd, esd->pcm_buf, chunk << hw->info.shift);
+            if (written == -1) {
+                if (errno == EINTR || errno == EAGAIN) {
+                    goto again;
+                }
+                qesd_logerr (errno, "write failed\n");
+                return NULL;
+            }
+
+            if (written != chunk << hw->info.shift) {
+                int wsamples = written >> hw->info.shift;
+                int wbytes = wsamples << hw->info.shift;
+                if (wbytes != written) {
+                    dolog ("warning: Misaligned write %d (requested %d), "
+                           "alignment %d\n",
+                           wbytes, written, hw->info.align + 1);
+                }
+                to_mix -= wsamples;
+                rpos = (rpos + wsamples) % hw->samples;
+                break;
+            }
+
+            rpos = (rpos + chunk) % hw->samples;
+            to_mix -= chunk;
+        }
+
+        if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
+            return NULL;
+        }
+
+        esd->rpos = rpos;
+        esd->live -= decr;
+        esd->decr += decr;
+    }
+
+ exit:
+    audio_pt_unlock (&esd->pt, AUDIO_FUNC);
+    return NULL;
+}
+
+static int qesd_run_out (HWVoiceOut *hw)
+{
+    int live, decr;
+    ESDVoiceOut *esd = (ESDVoiceOut *) hw;
+
+    if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
+        return 0;
+    }
+
+    live = audio_pcm_hw_get_live_out (hw);
+    decr = audio_MIN (live, esd->decr);
+    esd->decr -= decr;
+    esd->live = live - decr;
+    hw->rpos = esd->rpos;
+    if (esd->live > 0) {
+        audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
+    }
+    else {
+        audio_pt_unlock (&esd->pt, AUDIO_FUNC);
+    }
+    return decr;
+}
+
+static int qesd_write (SWVoiceOut *sw, void *buf, int len)
+{
+    return audio_pcm_sw_write (sw, buf, len);
+}
+
+static int qesd_init_out (HWVoiceOut *hw, audsettings_t *as)
+{
+    ESDVoiceOut *esd = (ESDVoiceOut *) hw;
+    audsettings_t obt_as = *as;
+    int esdfmt = ESD_STREAM | ESD_PLAY;
+    int err;
+    sigset_t set, old_set;
+
+    sigfillset (&set);
+
+    esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO;
+    switch (as->fmt) {
+    case AUD_FMT_S8:
+    case AUD_FMT_U8:
+        esdfmt |= ESD_BITS8;
+        obt_as.fmt = AUD_FMT_U8;
+        break;
+
+    case AUD_FMT_S32:
+    case AUD_FMT_U32:
+        dolog ("Will use 16 instead of 32 bit samples\n");
+
+    case AUD_FMT_S16:
+    case AUD_FMT_U16:
+    deffmt:
+        esdfmt |= ESD_BITS16;
+        obt_as.fmt = AUD_FMT_S16;
+        break;
+
+    default:
+        dolog ("Internal logic error: Bad audio format %d\n", as->fmt);
+#ifdef DEBUG_FMOD
+        abort ();
+#endif
+        goto deffmt;
+
+    }
+    obt_as.endianness = 0;
+
+    audio_pcm_init_info (&hw->info, &obt_as);
+
+    hw->samples = conf.samples;
+    esd->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
+    if (!esd->pcm_buf) {
+        dolog ("Could not allocate buffer (%d bytes)\n",
+               hw->samples << hw->info.shift);
+        return -1;
+    }
+
+    esd->fd = -1;
+    err = pthread_sigmask (SIG_BLOCK, &set, &old_set);
+    if (err) {
+        qesd_logerr (err, "pthread_sigmask failed\n");
+        goto fail1;
+    }
+
+    esd->fd = esd_play_stream (esdfmt, as->freq, conf.dac_host, NULL);
+    if (esd->fd < 0) {
+        qesd_logerr (errno, "esd_play_stream failed\n");
+        goto fail2;
+    }
+
+    if (audio_pt_init (&esd->pt, qesd_thread_out, esd, AUDIO_CAP, AUDIO_FUNC)) {
+        goto fail3;
+    }
+
+    err = pthread_sigmask (SIG_SETMASK, &old_set, NULL);
+    if (err) {
+        qesd_logerr (err, "pthread_sigmask(restore) failed\n");
+    }
+
+    return 0;
+
+ fail3:
+    if (close (esd->fd)) {
+        qesd_logerr (errno, "%s: close on esd socket(%d) failed\n",
+                     AUDIO_FUNC, esd->fd);
+    }
+    esd->fd = -1;
+
+ fail2:
+    err = pthread_sigmask (SIG_SETMASK, &old_set, NULL);
+    if (err) {
+        qesd_logerr (err, "pthread_sigmask(restore) failed\n");
+    }
+
+ fail1:
+    qemu_free (esd->pcm_buf);
+    esd->pcm_buf = NULL;
+    return -1;
+}
+
+static void qesd_fini_out (HWVoiceOut *hw)
+{
+    void *ret;
+    ESDVoiceOut *esd = (ESDVoiceOut *) hw;
+
+    audio_pt_lock (&esd->pt, AUDIO_FUNC);
+    esd->done = 1;
+    audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
+    audio_pt_join (&esd->pt, &ret, AUDIO_FUNC);
+
+    if (esd->fd >= 0) {
+        if (close (esd->fd)) {
+            qesd_logerr (errno, "failed to close esd socket\n");
+        }
+        esd->fd = -1;
+    }
+
+    audio_pt_fini (&esd->pt, AUDIO_FUNC);
+
+    qemu_free (esd->pcm_buf);
+    esd->pcm_buf = NULL;
+}
+
+static int qesd_ctl_out (HWVoiceOut *hw, int cmd, ...)
+{
+    (void) hw;
+    (void) cmd;
+    return 0;
+}
+
+/* capture */
+static void *qesd_thread_in (void *arg)
+{
+    ESDVoiceIn *esd = arg;
+    HWVoiceIn *hw = &esd->hw;
+    int threshold;
+
+    threshold = conf.divisor ? hw->samples / conf.divisor : 0;
+
+    for (;;) {
+        int incr, to_grab, wpos;
+
+        for (;;) {
+            if (esd->done) {
+                goto exit;
+            }
+
+            if (esd->dead > threshold) {
+                break;
+            }
+
+            if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) {
+                goto exit;
+            }
+        }
+
+        incr = to_grab = esd->dead;
+        wpos = hw->wpos;
+
+        if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) {
+            return NULL;
+        }
+
+        while (to_grab) {
+            ssize_t nread;
+            int chunk = audio_MIN (to_grab, hw->samples - wpos);
+            void *buf = advance (esd->pcm_buf, wpos);
+
+        again:
+            nread = read (esd->fd, buf, chunk << hw->info.shift);
+            if (nread == -1) {
+                if (errno == EINTR || errno == EAGAIN) {
+                    goto again;
+                }
+                qesd_logerr (errno, "read failed\n");
+                return NULL;
+            }
+
+            if (nread != chunk << hw->info.shift) {
+                int rsamples = nread >> hw->info.shift;
+                int rbytes = rsamples << hw->info.shift;
+                if (rbytes != nread) {
+                    dolog ("warning: Misaligned write %d (requested %d), "
+                           "alignment %d\n",
+                           rbytes, nread, hw->info.align + 1);
+                }
+                to_grab -= rsamples;
+                wpos = (wpos + rsamples) % hw->samples;
+                break;
+            }
+
+            hw->conv (hw->conv_buf + wpos, buf, nread >> hw->info.shift,
+                      &nominal_volume);
+            wpos = (wpos + chunk) % hw->samples;
+            to_grab -= chunk;
+        }
+
+        if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
+            return NULL;
+        }
+
+        esd->wpos = wpos;
+        esd->dead -= incr;
+        esd->incr += incr;
+    }
+
+ exit:
+    audio_pt_unlock (&esd->pt, AUDIO_FUNC);
+    return NULL;
+}
+
+static int qesd_run_in (HWVoiceIn *hw)
+{
+    int live, incr, dead;
+    ESDVoiceIn *esd = (ESDVoiceIn *) hw;
+
+    if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
+        return 0;
+    }
+
+    live = audio_pcm_hw_get_live_in (hw);
+    dead = hw->samples - live;
+    incr = audio_MIN (dead, esd->incr);
+    esd->incr -= incr;
+    esd->dead = dead - incr;
+    hw->wpos = esd->wpos;
+    if (esd->dead > 0) {
+        audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
+    }
+    else {
+        audio_pt_unlock (&esd->pt, AUDIO_FUNC);
+    }
+    return incr;
+}
+
+static int qesd_read (SWVoiceIn *sw, void *buf, int len)
+{
+    return audio_pcm_sw_read (sw, buf, len);
+}
+
+static int qesd_init_in (HWVoiceIn *hw, audsettings_t *as)
+{
+    ESDVoiceIn *esd = (ESDVoiceIn *) hw;
+    audsettings_t obt_as = *as;
+    int esdfmt = ESD_STREAM | ESD_RECORD;
+    int err;
+    sigset_t set, old_set;
+
+    sigfillset (&set);
+
+    esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO;
+    switch (as->fmt) {
+    case AUD_FMT_S8:
+    case AUD_FMT_U8:
+        esdfmt |= ESD_BITS8;
+        obt_as.fmt = AUD_FMT_U8;
+        break;
+
+    case AUD_FMT_S16:
+    case AUD_FMT_U16:
+        esdfmt |= ESD_BITS16;
+        obt_as.fmt = AUD_FMT_S16;
+        break;
+
+    case AUD_FMT_S32:
+    case AUD_FMT_U32:
+        dolog ("Will use 16 instead of 32 bit samples\n");
+        esdfmt |= ESD_BITS16;
+        obt_as.fmt = AUD_FMT_S16;
+        break;
+    }
+    obt_as.endianness = 0;
+
+    audio_pcm_init_info (&hw->info, &obt_as);
+
+    hw->samples = conf.samples;
+    esd->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
+    if (!esd->pcm_buf) {
+        dolog ("Could not allocate buffer (%d bytes)\n",
+               hw->samples << hw->info.shift);
+        return -1;
+    }
+
+    esd->fd = -1;
+
+    err = pthread_sigmask (SIG_BLOCK, &set, &old_set);
+    if (err) {
+        qesd_logerr (err, "pthread_sigmask failed\n");
+        goto fail1;
+    }
+
+    esd->fd = esd_record_stream (esdfmt, as->freq, conf.adc_host, NULL);
+    if (esd->fd < 0) {
+        qesd_logerr (errno, "esd_record_stream failed\n");
+        goto fail2;
+    }
+
+    if (audio_pt_init (&esd->pt, qesd_thread_in, esd, AUDIO_CAP, AUDIO_FUNC)) {
+        goto fail3;
+    }
+
+    err = pthread_sigmask (SIG_SETMASK, &old_set, NULL);
+    if (err) {
+        qesd_logerr (err, "pthread_sigmask(restore) failed\n");
+    }
+
+    return 0;
+
+ fail3:
+    if (close (esd->fd)) {
+        qesd_logerr (errno, "%s: close on esd socket(%d) failed\n",
+                     AUDIO_FUNC, esd->fd);
+    }
+    esd->fd = -1;
+
+ fail2:
+    err = pthread_sigmask (SIG_SETMASK, &old_set, NULL);
+    if (err) {
+        qesd_logerr (err, "pthread_sigmask(restore) failed\n");
+    }
+
+ fail1:
+    qemu_free (esd->pcm_buf);
+    esd->pcm_buf = NULL;
+    return -1;
+}
+
+static void qesd_fini_in (HWVoiceIn *hw)
+{
+    void *ret;
+    ESDVoiceIn *esd = (ESDVoiceIn *) hw;
+
+    audio_pt_lock (&esd->pt, AUDIO_FUNC);
+    esd->done = 1;
+    audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
+    audio_pt_join (&esd->pt, &ret, AUDIO_FUNC);
+
+    if (esd->fd >= 0) {
+        if (close (esd->fd)) {
+            qesd_logerr (errno, "failed to close esd socket\n");
+        }
+        esd->fd = -1;
+    }
+
+    audio_pt_fini (&esd->pt, AUDIO_FUNC);
+
+    qemu_free (esd->pcm_buf);
+    esd->pcm_buf = NULL;
+}
+
+static int qesd_ctl_in (HWVoiceIn *hw, int cmd, ...)
+{
+    (void) hw;
+    (void) cmd;
+    return 0;
+}
+
+/* common */
+static void *qesd_audio_init (void)
+{
+    return &conf;
+}
+
+static void qesd_audio_fini (void *opaque)
+{
+    (void) opaque;
+    ldebug ("esd_fini");
+}
+
+struct audio_option qesd_options[] = {
+    {"SAMPLES", AUD_OPT_INT, &conf.samples,
+     "buffer size in samples", NULL, 0},
+
+    {"DIVISOR", AUD_OPT_INT, &conf.divisor,
+     "threshold divisor", NULL, 0},
+
+    {"DAC_HOST", AUD_OPT_STR, &conf.dac_host,
+     "playback host", NULL, 0},
+
+    {"ADC_HOST", AUD_OPT_STR, &conf.adc_host,
+     "capture host", NULL, 0},
+
+    {NULL, 0, NULL, NULL, NULL, 0}
+};
+
+struct audio_pcm_ops qesd_pcm_ops = {
+    qesd_init_out,
+    qesd_fini_out,
+    qesd_run_out,
+    qesd_write,
+    qesd_ctl_out,
+
+    qesd_init_in,
+    qesd_fini_in,
+    qesd_run_in,
+    qesd_read,
+    qesd_ctl_in,
+};
+
+struct audio_driver esd_audio_driver = {
+    INIT_FIELD (name           = ) "esd",
+    INIT_FIELD (descr          = )
+    "http://en.wikipedia.org/wiki/Esound",
+    INIT_FIELD (options        = ) qesd_options,
+    INIT_FIELD (init           = ) qesd_audio_init,
+    INIT_FIELD (fini           = ) qesd_audio_fini,
+    INIT_FIELD (pcm_ops        = ) &qesd_pcm_ops,
+    INIT_FIELD (can_be_default = ) 0,
+    INIT_FIELD (max_voices_out = ) INT_MAX,
+    INIT_FIELD (max_voices_in  = ) INT_MAX,
+    INIT_FIELD (voice_size_out = ) sizeof (ESDVoiceOut),
+    INIT_FIELD (voice_size_in  = ) sizeof (ESDVoiceIn)
+};

Modified: trunk/src/host/qemu-neo1973/audio/ossaudio.c
===================================================================
--- trunk/src/host/qemu-neo1973/audio/ossaudio.c	2008-01-14 20:40:58 UTC (rev 3831)
+++ trunk/src/host/qemu-neo1973/audio/ossaudio.c	2008-01-14 23:24:21 UTC (rev 3832)
@@ -150,7 +150,7 @@
 {
     switch (ossfmt) {
     case AFMT_S8:
-        *endianness =0;
+        *endianness = 0;
         *fmt = AUD_FMT_S8;
         break;
 

Modified: trunk/src/host/qemu-neo1973/audio/wavaudio.c
===================================================================
--- trunk/src/host/qemu-neo1973/audio/wavaudio.c	2008-01-14 20:40:58 UTC (rev 3831)
+++ trunk/src/host/qemu-neo1973/audio/wavaudio.c	2008-01-14 23:24:21 UTC (rev 3832)
@@ -44,7 +44,7 @@
         44100,
         2,
         AUD_FMT_S16,
-        AUDIO_HOST_ENDIANNESS
+        0
     },
     "qemu.wav"
 };

Modified: trunk/src/host/qemu-neo1973/block-vmdk.c
===================================================================
--- trunk/src/host/qemu-neo1973/block-vmdk.c	2008-01-14 20:40:58 UTC (rev 3831)
+++ trunk/src/host/qemu-neo1973/block-vmdk.c	2008-01-14 23:24:21 UTC (rev 3832)
@@ -341,6 +341,8 @@
         p_name += sizeof("parentFileNameHint") + 1;
         if ((end_name = strchr(p_name,'\"')) == 0)
             return -1;
+        if ((end_name - p_name) > sizeof (s->hd->backing_file) - 1)
+            return -1;
 
         strncpy(s->hd->backing_file, p_name, end_name - p_name);
         if (stat(s->hd->backing_file, &file_buf) != 0) {

Modified: trunk/src/host/qemu-neo1973/configure
===================================================================
--- trunk/src/host/qemu-neo1973/configure	2008-01-14 20:40:58 UTC (rev 3831)
+++ trunk/src/host/qemu-neo1973/configure	2008-01-14 23:24:21 UTC (rev 3832)
@@ -85,10 +85,13 @@
 gdbstub="yes"
 slirp="yes"
 adlib="no"
+ac97="no"
+gus="no"
 oss="no"
 dsound="no"
 coreaudio="no"
 alsa="no"
+esd="no"
 fmod="no"
 fmod_lib=""
 fmod_inc=""
@@ -153,6 +156,7 @@
 cocoa="yes"
 coreaudio="yes"
 OS_CFLAGS="-mdynamic-no-pic"
+OS_LDFLAGS="-framework CoreFoundation -framework IOKit"
 ;;
 SunOS)
     solaris="yes"
@@ -262,6 +266,8 @@
   ;;
   --enable-alsa) alsa="yes"
   ;;
+  --enable-esd) esd="yes"
+  ;;
   --enable-dsound) dsound="yes"
   ;;
   --enable-fmod) fmod="yes"
@@ -278,6 +284,10 @@
   ;;
   --enable-adlib) adlib="yes"
   ;;
+  --enable-ac97) ac97="yes"
+  ;;
+  --enable-gus) gus="yes"
+  ;;
   --disable-kqemu) kqemu="no"
   ;;
   --enable-profiler) profiler="yes"
@@ -406,8 +416,11 @@
 echo "  --enable-cocoa           enable COCOA (Mac OS X only)"
 echo "  --enable-mingw32         enable Win32 cross compilation with mingw32"
 echo "  --enable-adlib           enable Adlib emulation"
+echo "  --enable-ac97            enable AC97 emulation"
+echo "  --enable-gus             enable Gravis Ultrasound emulation"
 echo "  --enable-coreaudio       enable Coreaudio audio driver"
 echo "  --enable-alsa            enable ALSA audio driver"
+echo "  --enable-esd             enable EsoundD audio driver"
 echo "  --enable-fmod            enable FMOD audio driver"
 echo "  --enable-dsound          enable DirectSound audio driver"
 echo "  --disable-vnc-tls        disable TLS encryption for VNC server"
@@ -758,8 +771,11 @@
 fi
 echo "mingw32 support   $mingw32"
 echo "Adlib support     $adlib"
+echo "AC97 support      $ac97"
+echo "GUS support       $gus"
 echo "CoreAudio support $coreaudio"
 echo "ALSA support      $alsa"
+echo "EsounD support    $esd"
 echo "DSound support    $dsound"
 if test "$fmod" = "yes"; then
     if test -z $fmod_lib || test -z $fmod_inc; then
@@ -933,6 +949,14 @@
   echo "CONFIG_ADLIB=yes" >> $config_mak
   echo "#define CONFIG_ADLIB 1" >> $config_h
 fi
+if test "$ac97" = "yes" ; then
+  echo "CONFIG_AC97=yes" >> $config_mak
+  echo "#define CONFIG_AC97 1" >> $config_h
+fi
+if test "$gus" = "yes" ; then
+  echo "CONFIG_GUS=yes" >> $config_mak
+  echo "#define CONFIG_GUS 1" >> $config_h
+fi
 if test "$oss" = "yes" ; then
   echo "CONFIG_OSS=yes" >> $config_mak
   echo "#define CONFIG_OSS 1" >> $config_h
@@ -945,6 +969,10 @@
   echo "CONFIG_ALSA=yes" >> $config_mak
   echo "#define CONFIG_ALSA 1" >> $config_h
 fi
+if test "$esd" = "yes" ; then
+  echo "CONFIG_ESD=yes" >> $config_mak
+  echo "#define CONFIG_ESD 1" >> $config_h
+fi
 if test "$dsound" = "yes" ; then
   echo "CONFIG_DSOUND=yes" >> $config_mak
   echo "#define CONFIG_DSOUND 1" >> $config_h

Added: trunk/src/host/qemu-neo1973/hw/ac97.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/ac97.c	2008-01-14 20:40:58 UTC (rev 3831)
+++ trunk/src/host/qemu-neo1973/hw/ac97.c	2008-01-14 23:24:21 UTC (rev 3832)
@@ -0,0 +1,1349 @@
+/*
+ * Copyright (C) 2006 InnoTek Systemberatung GmbH
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License as published by the Free Software Foundation,
+ * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
+ * distribution. VirtualBox OSE is distributed in the hope that it will
+ * be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * If you received this file as part of a commercial VirtualBox
+ * distribution, then only the terms of your commercial VirtualBox
+ * license agreement apply instead of the previous paragraph.
+ */
+
+#include "hw.h"
+#include "audiodev.h"
+#include "audio/audio.h"
+#include "pci.h"
+
+enum {
+    AC97_Reset                     = 0x00,
+    AC97_Master_Volume_Mute        = 0x02,
+    AC97_Headphone_Volume_Mute     = 0x04,
+    AC97_Master_Volume_Mono_Mute   = 0x06,
+    AC97_Master_Tone_RL            = 0x08,
+    AC97_PC_BEEP_Volume_Mute       = 0x0A,
+    AC97_Phone_Volume_Mute         = 0x0C,
+    AC97_Mic_Volume_Mute           = 0x0E,
+    AC97_Line_In_Volume_Mute       = 0x10,
+    AC97_CD_Volume_Mute            = 0x12,
+    AC97_Video_Volume_Mute         = 0x14,
+    AC97_Aux_Volume_Mute           = 0x16,
+    AC97_PCM_Out_Volume_Mute       = 0x18,
+    AC97_Record_Select             = 0x1A,
+    AC97_Record_Gain_Mute          = 0x1C,
+    AC97_Record_Gain_Mic_Mute      = 0x1E,
+    AC97_General_Purpose           = 0x20,
+    AC97_3D_Control                = 0x22,
+    AC97_AC_97_RESERVED            = 0x24,
+    AC97_Powerdown_Ctrl_Stat       = 0x26,
+    AC97_Extended_Audio_ID         = 0x28,
+    AC97_Extended_Audio_Ctrl_Stat  = 0x2A,
+    AC97_PCM_Front_DAC_Rate        = 0x2C,
+    AC97_PCM_Surround_DAC_Rate     = 0x2E,
+    AC97_PCM_LFE_DAC_Rate          = 0x30,
+    AC97_PCM_LR_ADC_Rate           = 0x32,
+    AC97_MIC_ADC_Rate              = 0x34,
+    AC97_6Ch_Vol_C_LFE_Mute        = 0x36,
+    AC97_6Ch_Vol_L_R_Surround_Mute = 0x38,
+    AC97_Vendor_Reserved           = 0x58,
+    AC97_Vendor_ID1                = 0x7c,
+    AC97_Vendor_ID2                = 0x7e
+};
+
+#define SOFT_VOLUME
+#define SR_FIFOE 16             /* rwc */
+#define SR_BCIS  8              /* rwc */
+#define SR_LVBCI 4              /* rwc */
+#define SR_CELV  2              /* ro */
+#define SR_DCH   1              /* ro */
+#define SR_VALID_MASK ((1 << 5) - 1)
+#define SR_WCLEAR_MASK (SR_FIFOE | SR_BCIS | SR_LVBCI)
+#define SR_RO_MASK (SR_DCH | SR_CELV)
+#define SR_INT_MASK (SR_FIFOE | SR_BCIS | SR_LVBCI)
+
+#define CR_IOCE  16             /* rw */
+#define CR_FEIE  8              /* rw */
+#define CR_LVBIE 4              /* rw */
+#define CR_RR    2              /* rw */
+#define CR_RPBM  1              /* rw */
+#define CR_VALID_MASK ((1 << 5) - 1)
+#define CR_DONT_CLEAR_MASK (CR_IOCE | CR_FEIE | CR_LVBIE)
+
+#define GC_WR    4              /* rw */
+#define GC_CR    2              /* rw */
+#define GC_VALID_MASK ((1 << 6) - 1)
+
+#define GS_MD3   (1<<17)        /* rw */
+#define GS_AD3   (1<<16)        /* rw */
+#define GS_RCS   (1<<15)        /* rwc */
+#define GS_B3S12 (1<<14)        /* ro */
+#define GS_B2S12 (1<<13)        /* ro */
+#define GS_B1S12 (1<<12)        /* ro */
+#define GS_S1R1  (1<<11)        /* rwc */
+#define GS_S0R1  (1<<10)        /* rwc */
+#define GS_S1CR  (1<<9)         /* ro */
+#define GS_S0CR  (1<<8)         /* ro */
+#define GS_MINT  (1<<7)         /* ro */
+#define GS_POINT (1<<6)         /* ro */
+#define GS_PIINT (1<<5)         /* ro */
+#define GS_RSRVD ((1<<4)|(1<<3))
+#define GS_MOINT (1<<2)         /* ro */
+#define GS_MIINT (1<<1)         /* ro */
+#define GS_GSCI  1              /* rwc */
+#define GS_RO_MASK (GS_B3S12|                   \
+                    GS_B2S12|                   \
+                    GS_B1S12|                   \
+                    GS_S1CR|                    \
+                    GS_S0CR|                    \
+                    GS_MINT|                    \
+                    GS_POINT|                   \
+                    GS_PIINT|                   \
+                    GS_RSRVD|                   \
+                    GS_MOINT|                   \
+                    GS_MIINT)
+#define GS_VALID_MASK ((1 << 18) - 1)
+#define GS_WCLEAR_MASK (GS_RCS|GS_S1R1|GS_S0R1|GS_GSCI)
+
+#define BD_IOC (1<<31)
+#define BD_BUP (1<<30)
+
+#define EACS_VRA 1
+#define EACS_VRM 8
+
+#define VOL_MASK 0x1f
+#define MUTE_SHIFT 15
+
+#define REC_MASK 7
+enum {
+    REC_MIC = 0,
+    REC_CD,
+    REC_VIDEO,
+    REC_AUX,
+    REC_LINE_IN,
+    REC_STEREO_MIX,
+    REC_MONO_MIX,
+    REC_PHONE
+};
+
+typedef struct BD {
+    uint32_t addr;
+    uint32_t ctl_len;
+} BD;
+
+typedef struct AC97BusMasterRegs {
+    uint32_t bdbar;             /* rw 0 */
+    uint8_t civ;                /* ro 0 */
+    uint8_t lvi;                /* rw 0 */
+    uint16_t sr;                /* rw 1 */
+    uint16_t picb;              /* ro 0 */
+    uint8_t piv;                /* ro 0 */
+    uint8_t cr;                 /* rw 0 */
+    unsigned int bd_valid;
+    BD bd;
+} AC97BusMasterRegs;
+
+typedef struct AC97LinkState {
+    PCIDevice *pci_dev;
+    QEMUSoundCard card;
+    uint32_t glob_cnt;
+    uint32_t glob_sta;
+    uint32_t cas;
+    uint32_t last_samp;
+    AC97BusMasterRegs bm_regs[3];
+    uint8_t mixer_data[256];
+    SWVoiceIn *voice_pi;
+    SWVoiceOut *voice_po;
+    SWVoiceIn *voice_mc;
+    uint8_t silence[128];
+    uint32_t base[2];
+    int bup_flag;
+} AC97LinkState;
+
+enum {
+    BUP_SET = 1,
+    BUP_LAST = 2
+};
+
+#ifdef DEBUG_AC97
+#define dolog(...) AUD_log ("ac97", __VA_ARGS__)
+#else
+#define dolog(...)
+#endif
+
+typedef struct PCIAC97LinkState {
+    PCIDevice dev;
+    AC97LinkState ac97;
+} PCIAC97LinkState;
+
+#define MKREGS(prefix, start)                   \
+enum {                                          \
+    prefix ## _BDBAR = start,                   \
+    prefix ## _CIV = start + 4,                 \
+    prefix ## _LVI = start + 5,                 \
+    prefix ## _SR = start + 6,                  \
+    prefix ## _PICB = start + 8,                \
+    prefix ## _PIV = start + 10,                \
+    prefix ## _CR = start + 11                  \
+}
+
+enum {
+    PI_INDEX = 0,
+    PO_INDEX,
+    MC_INDEX,
+    LAST_INDEX
+};
+
+MKREGS (PI, PI_INDEX * 16);
+MKREGS (PO, PO_INDEX * 16);
+MKREGS (MC, MC_INDEX * 16);
+
+enum {
+    GLOB_CNT = 0x2c,
+    GLOB_STA = 0x30,
+    CAS      = 0x34
+};
+
+#define GET_BM(index) (((index) >> 4) & 3)
+
+static void po_callback (void *opaque, int free);
+static void pi_callback (void *opaque, int avail);
+static void mc_callback (void *opaque, int avail);
+
+static void warm_reset (AC97LinkState *s)
+{
+    (void) s;
+}
+
+static void cold_reset (AC97LinkState * s)
+{
+    (void) s;
+}
+
+static void fetch_bd (AC97LinkState *s, AC97BusMasterRegs *r)
+{
+    uint8_t b[8];
+
+    cpu_physical_memory_read (r->bdbar + r->civ * 8, b, 8);
+    r->bd_valid = 1;
+    r->bd.addr = le32_to_cpu (*(uint32_t *) &b[0]) & ~3;
+    r->bd.ctl_len = le32_to_cpu (*(uint32_t *) &b[4]);
+    r->picb = r->bd.ctl_len & 0xffff;
+    dolog ("bd %2d addr=%#x ctl=%#06x len=%#x(%d bytes)\n",
+           r->civ, r->bd.addr, r->bd.ctl_len >> 16,
+           r->bd.ctl_len & 0xffff,
+           (r->bd.ctl_len & 0xffff) << 1);
+}
+
+static void update_sr (AC97LinkState *s, AC97BusMasterRegs *r, uint32_t new_sr)
+{
+    int event = 0;
+    int level = 0;
+    uint32_t new_mask = new_sr & SR_INT_MASK;
+    uint32_t old_mask = r->sr & SR_INT_MASK;
+    uint32_t masks[] = {GS_PIINT, GS_POINT, GS_MINT};
+
+    if (new_mask ^ old_mask) {
+        /** @todo is IRQ deasserted when only one of status bits is cleared? */
+        if (!new_mask) {
+            event = 1;
+            level = 0;
+        }
+        else {
+            if ((new_mask & SR_LVBCI) && (r->cr & CR_LVBIE)) {
+                event = 1;
+                level = 1;
+            }
+            if ((new_mask & SR_BCIS) && (r->cr & CR_IOCE)) {
+                event = 1;
+                level = 1;
+            }
+        }
+    }
+
+    r->sr = new_sr;
+
+    dolog ("IOC%d LVB%d sr=%#x event=%d level=%d\n",
+           r->sr & SR_BCIS, r->sr & SR_LVBCI,
+           r->sr,
+           event, level);
+
+    if (!event)
+        return;
+
+    if (level) {
+        s->glob_sta |= masks[r - s->bm_regs];
+        dolog ("set irq level=1\n");
+        qemu_set_irq(s->pci_dev->irq[0], 1);
+    }
+    else {
+        s->glob_sta &= ~masks[r - s->bm_regs];
+        dolog ("set irq level=0\n");
+        qemu_set_irq(s->pci_dev->irq[0], 0);
+    }
+}
+
+static void voice_set_active (AC97LinkState *s, int bm_index, int on)
+{
+    switch (bm_index) {
+    case PI_INDEX:
+        AUD_set_active_in (s->voice_pi, on);
+        break;
+
+    case PO_INDEX:
+        AUD_set_active_out (s->voice_po, on);
+        break;
+
+    case MC_INDEX:
+        AUD_set_active_in (s->voice_mc, on);
+        break;
+
+    default:
+        AUD_log ("ac97", "invalid bm_index(%d) in voice_set_active", bm_index);
+        break;
+    }
+}
+
+static void reset_bm_regs (AC97LinkState *s, AC97BusMasterRegs *r)
+{
+    dolog ("reset_bm_regs\n");
+    r->bdbar = 0;
+    r->civ = 0;
+    r->lvi = 0;
+    /** todo do we need to do that? */
+    update_sr (s, r, SR_DCH);
+    r->picb = 0;
+    r->piv = 0;
+    r->cr = r->cr & CR_DONT_CLEAR_MASK;
+    r->bd_valid = 0;
+
+    voice_set_active (s, r - s->bm_regs, 0);
+    memset (s->silence, 0, sizeof (s->silence));
+}
+
+static void mixer_store (AC97LinkState *s, uint32_t i, uint16_t v)
+{
+    if (i + 2 > sizeof (s->mixer_data)) {
+        dolog ("mixer_store: index %d out of bounds %d\n",
+               i, sizeof (s->mixer_data));
+        return;
+    }
+
+    s->mixer_data[i + 0] = v & 0xff;
+    s->mixer_data[i + 1] = v >> 8;
+}
+
+static uint16_t mixer_load (AC97LinkState *s, uint32_t i)
+{
+    uint16_t val = 0xffff;
+
+    if (i + 2 > sizeof (s->mixer_data)) {
+        dolog ("mixer_store: index %d out of bounds %d\n",
+               i, sizeof (s->mixer_data));
+    }
+    else {
+        val = s->mixer_data[i + 0] | (s->mixer_data[i + 1] << 8);
+    }
+
+    return val;
+}
+
+static void open_voice (AC97LinkState *s, int index, int freq)
+{
+    audsettings_t as;
+
+    as.freq = freq;
+    as.nchannels = 2;
+    as.fmt = AUD_FMT_S16;
+    as.endianness = 0;
+
+    switch (index) {
+    case PI_INDEX:
+        s->voice_pi = AUD_open_in (
+            &s->card,
+            s->voice_pi,
+            "ac97.pi",
+            s,
+            pi_callback,
+            &as
+            );
+        break;
+
+    case PO_INDEX:
+        s->voice_po = AUD_open_out (
+            &s->card,
+            s->voice_po,
+            "ac97.po",
+            s,
+            po_callback,
+            &as
+            );
+        break;
+
+    case MC_INDEX:
+        s->voice_mc = AUD_open_in (
+            &s->card,
+            s->voice_mc,
+            "ac97.mc",
+            s,
+            mc_callback,
+            &as
+            );
+        break;
+    }
+}
+
+static void reset_voices (AC97LinkState *s, uint8_t active[LAST_INDEX])
+{
+    uint16_t freq;
+
+    freq = mixer_load (s, AC97_PCM_LR_ADC_Rate);
+    open_voice (s, PI_INDEX, freq);
+    AUD_set_active_in (s->voice_pi, active[PI_INDEX]);
+
+    freq = mixer_load (s, AC97_PCM_Front_DAC_Rate);
+    open_voice (s, PO_INDEX, freq);
+    AUD_set_active_out (s->voice_po, active[PO_INDEX]);
+
+    freq = mixer_load (s, AC97_MIC_ADC_Rate);
+    open_voice (s, MC_INDEX, freq);
+    AUD_set_active_in (s->voice_mc, active[MC_INDEX]);
+}
+
+#ifdef USE_MIXER
+static void set_volume (AC97LinkState *s, int index,
+                        audmixerctl_t mt, uint32_t val)
+{
+    int mute = (val >> MUTE_SHIFT) & 1;
+    uint8_t rvol = VOL_MASK - (val & VOL_MASK);
+    uint8_t lvol = VOL_MASK - ((val >> 8) & VOL_MASK);
+    rvol = 255 * rvol / VOL_MASK;
+    lvol = 255 * lvol / VOL_MASK;
+
+#ifdef SOFT_VOLUME
+    if (index == AC97_Master_Volume_Mute) {
+        AUD_set_volume_out (s->voice_po, mute, lvol, rvol);
+    }
+    else {
+        AUD_set_volume (mt, &mute, &lvol, &rvol);
+    }
+#else
+    AUD_set_volume (mt, &mute, &lvol, &rvol);
+#endif
+
+    rvol = VOL_MASK - ((VOL_MASK * rvol) / 255);
+    lvol = VOL_MASK - ((VOL_MASK * lvol) / 255);
+    mixer_store (s, index, val);
+}
+
+static audrecsource_t ac97_to_aud_record_source (uint8_t i)
+{
+    switch (i) {
+    case REC_MIC:
+        return AUD_REC_MIC;
+
+    case REC_CD:
+        return AUD_REC_CD;
+
+    case REC_VIDEO:
+        return AUD_REC_VIDEO;
+
+    case REC_AUX:
+        return AUD_REC_AUX;
+
+    case REC_LINE_IN:
+        return AUD_REC_LINE_IN;
+
+    case REC_PHONE:
+        return AUD_REC_PHONE;
+
+    default:
+        dolog ("Unknown record source %d, using MIC\n", i);
+        return AUD_REC_MIC;
+    }
+}
+
+static uint8_t aud_to_ac97_record_source (audrecsource_t rs)
+{
+    switch (rs) {
+    case AUD_REC_MIC:
+        return REC_MIC;
+
+    case AUD_REC_CD:
+        return REC_CD;
+
+    case AUD_REC_VIDEO:
+        return REC_VIDEO;
+
+    case AUD_REC_AUX:
+        return REC_AUX;
+
+    case AUD_REC_LINE_IN:
+        return REC_LINE_IN;
+
+    case AUD_REC_PHONE:
+        return REC_PHONE;
+
+    default:
+        dolog ("Unknown audio recording source %d using MIC\n", rs);
+        return REC_MIC;
+    }
+}
+
+static void record_select (AC97LinkState *s, uint32_t val)
+{
+    uint8_t rs = val & REC_MASK;
+    uint8_t ls = (val >> 8) & REC_MASK;
+    audrecsource_t ars = ac97_to_aud_record_source (rs);
+    audrecsource_t als = ac97_to_aud_record_source (ls);
+    AUD_set_record_source (&als, &ars);
+    rs = aud_to_ac97_record_source (ars);
+    ls = aud_to_ac97_record_source (als);
+    mixer_store (s, AC97_Record_Select, rs | (ls << 8));
+}
+#endif
+
+static void mixer_reset (AC97LinkState *s)
+{
+    uint8_t active[LAST_INDEX];
+
+    dolog ("mixer_reset\n");
+    memset (s->mixer_data, 0, sizeof (s->mixer_data));
+    memset (active, 0, sizeof (active));
+    mixer_store (s, AC97_Reset                   , 0x0000); /* 6940 */
+    mixer_store (s, AC97_Master_Volume_Mono_Mute , 0x8000);
+    mixer_store (s, AC97_PC_BEEP_Volume_Mute     , 0x0000);
+
+    mixer_store (s, AC97_Phone_Volume_Mute       , 0x8008);
+    mixer_store (s, AC97_Mic_Volume_Mute         , 0x8008);
+    mixer_store (s, AC97_CD_Volume_Mute          , 0x8808);
+    mixer_store (s, AC97_Aux_Volume_Mute         , 0x8808);
+    mixer_store (s, AC97_Record_Gain_Mic_Mute    , 0x8000);
+    mixer_store (s, AC97_General_Purpose         , 0x0000);
+    mixer_store (s, AC97_3D_Control              , 0x0000);
+    mixer_store (s, AC97_Powerdown_Ctrl_Stat     , 0x000f);
+
+    /*
+     * Sigmatel 9700 (STAC9700)
+     */
+    mixer_store (s, AC97_Vendor_ID1              , 0x8384);
+    mixer_store (s, AC97_Vendor_ID2              , 0x7600); /* 7608 */
+
+    mixer_store (s, AC97_Extended_Audio_ID       , 0x0809);
+    mixer_store (s, AC97_Extended_Audio_Ctrl_Stat, 0x0009);
+    mixer_store (s, AC97_PCM_Front_DAC_Rate      , 0xbb80);
+    mixer_store (s, AC97_PCM_Surround_DAC_Rate   , 0xbb80);
+    mixer_store (s, AC97_PCM_LFE_DAC_Rate        , 0xbb80);
+    mixer_store (s, AC97_PCM_LR_ADC_Rate         , 0xbb80);
+    mixer_store (s, AC97_MIC_ADC_Rate            , 0xbb80);
+
+#ifdef USE_MIXER
+    record_select (s, 0);
+    set_volume (s, AC97_Master_Volume_Mute, AUD_MIXER_VOLUME  , 0x8000);
+    set_volume (s, AC97_PCM_Out_Volume_Mute, AUD_MIXER_PCM    , 0x8808);
+    set_volume (s, AC97_Line_In_Volume_Mute, AUD_MIXER_LINE_IN, 0x8808);
+#endif
+    reset_voices (s, active);
+}
+
+/**
+ * Native audio mixer
+ * I/O Reads
+ */
+static uint32_t nam_readb (void *opaque, uint32_t addr)
+{
+    PCIAC97LinkState *d = opaque;
+    AC97LinkState *s = &d->ac97;
+    dolog ("U nam readb %#x\n", addr);
+    s->cas = 0;
+    return ~0U;
+}
+
+static uint32_t nam_readw (void *opaque, uint32_t addr)
+{
+    PCIAC97LinkState *d = opaque;
+    AC97LinkState *s = &d->ac97;
+    uint32_t val = ~0U;
+    uint32_t index = addr - s->base[0];
+    s->cas = 0;
+    val = mixer_load (s, index);
+    return val;
+}
+
+static uint32_t nam_readl (void *opaque, uint32_t addr)
+{
+    PCIAC97LinkState *d = opaque;
+    AC97LinkState *s = &d->ac97;
+    dolog ("U nam readl %#x\n", addr);
+    s->cas = 0;
+    return ~0U;
+}
+
+/**
+ * Native audio mixer
+ * I/O Writes
+ */
+static void nam_writeb (void *opaque, uint32_t addr, uint32_t val)
+{
+    PCIAC97LinkState *d = opaque;
+    AC97LinkState *s = &d->ac97;
+    dolog ("U nam writeb %#x <- %#x\n", addr, val);
+    s->cas = 0;
+}
+
+static void nam_writew (void *opaque, uint32_t addr, uint32_t val)
+{
+    PCIAC97LinkState *d = opaque;
+    AC97LinkState *s = &d->ac97;
+    uint32_t index = addr - s->base[0];
+    s->cas = 0;
+    switch (index) {
+    case AC97_Reset:
+        mixer_reset (s);
+        break;
+    case AC97_Powerdown_Ctrl_Stat:
+        val &= ~0xf;
+        val |= mixer_load (s, index) & 0xf;
+        mixer_store (s, index, val);
+        break;
+#ifdef USE_MIXER
+    case AC97_Master_Volume_Mute:
+        set_volume (s, index, AUD_MIXER_VOLUME, val);
+        break;
+    case AC97_PCM_Out_Volume_Mute:
+        set_volume (s, index, AUD_MIXER_PCM, val);
+        break;
+    case AC97_Line_In_Volume_Mute:
+        set_volume (s, index, AUD_MIXER_LINE_IN, val);
+        break;
+    case AC97_Record_Select:
+        record_select (s, val);
+        break;
+#endif
+    case AC97_Vendor_ID1:
+    case AC97_Vendor_ID2:
+        dolog ("Attempt to write vendor ID to %#x\n", val);
+        break;
+    case AC97_Extended_Audio_ID:
+        dolog ("Attempt to write extended audio ID to %#x\n", val);
+        break;
+    case AC97_Extended_Audio_Ctrl_Stat:
+        if (!(val & EACS_VRA)) {
+            mixer_store (s, AC97_PCM_Front_DAC_Rate, 0xbb80);
+            mixer_store (s, AC97_PCM_LR_ADC_Rate,    0xbb80);
+            open_voice (s, PI_INDEX, 48000);
+            open_voice (s, PO_INDEX, 48000);
+        }
+        if (!(val & EACS_VRM)) {
+            mixer_store (s, AC97_MIC_ADC_Rate, 0xbb80);
+            open_voice (s, MC_INDEX, 48000);
+        }
+        dolog ("Setting extended audio control to %#x\n", val);
+        mixer_store (s, AC97_Extended_Audio_Ctrl_Stat, val);
+        break;
+    case AC97_PCM_Front_DAC_Rate:
+        if (mixer_load (s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA) {
+            mixer_store (s, index, val);
+            dolog ("Set front DAC rate to %d\n", val);
+            open_voice (s, PO_INDEX, val);
+        }
+        else {
+            dolog ("Attempt to set front DAC rate to %d, "
+                   "but VRA is not set\n",
+                   val);
+        }
+        break;
+    case AC97_MIC_ADC_Rate:
+        if (mixer_load (s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRM) {
+            mixer_store (s, index, val);
+            dolog ("Set MIC ADC rate to %d\n", val);
+            open_voice (s, MC_INDEX, val);
+        }
+        else {
+            dolog ("Attempt to set MIC ADC rate to %d, "
+                   "but VRM is not set\n",
+                   val);
+        }
+        break;
+    case AC97_PCM_LR_ADC_Rate:
+        if (mixer_load (s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA) {
+            mixer_store (s, index, val);
+            dolog ("Set front LR ADC rate to %d\n", val);
+            open_voice (s, PI_INDEX, val);
+        }
+        else {
+            dolog ("Attempt to set LR ADC rate to %d, but VRA is not set\n",
+                    val);
+        }
+        break;
+    default:
+        dolog ("U nam writew %#x <- %#x\n", addr, val);
+        mixer_store (s, index, val);
+        break;
+    }
+}
+
+static void nam_writel (void *opaque, uint32_t addr, uint32_t val)
+{
+    PCIAC97LinkState *d = opaque;
+    AC97LinkState *s = &d->ac97;
+    dolog ("U nam writel %#x <- %#x\n", addr, val);
+    s->cas = 0;
+}
+
+/**
+ * Native audio bus master
+ * I/O Reads
+ */
+static uint32_t nabm_readb (void *opaque, uint32_t addr)
+{
+    PCIAC97LinkState *d = opaque;
+    AC97LinkState *s = &d->ac97;
+    AC97BusMasterRegs *r = NULL;
+    uint32_t index = addr - s->base[1];
+    uint32_t val = ~0U;
+
+    switch (index) {
+    case CAS:
+        dolog ("CAS %d\n", s->cas);
+        val = s->cas;
+        s->cas = 1;
+        break;
+    case PI_CIV:
+    case PO_CIV:
+    case MC_CIV:
+        r = &s->bm_regs[GET_BM (index)];
+        val = r->civ;
+        dolog ("CIV[%d] -> %#x\n", GET_BM (index), val);
+        break;
+    case PI_LVI:
+    case PO_LVI:
+    case MC_LVI:
+        r = &s->bm_regs[GET_BM (index)];
+        val = r->lvi;
+        dolog ("LVI[%d] -> %#x\n", GET_BM (index), val);
+        break;
+    case PI_PIV:
+    case PO_PIV:
+    case MC_PIV:
+        r = &s->bm_regs[GET_BM (index)];
+        val = r->piv;
+        dolog ("PIV[%d] -> %#x\n", GET_BM (index), val);
+        break;
+    case PI_CR:
+    case PO_CR:
+    case MC_CR:
+        r = &s->bm_regs[GET_BM (index)];
+        val = r->cr;
+        dolog ("CR[%d] -> %#x\n", GET_BM (index), val);
+        break;
+    case PI_SR:
+    case PO_SR:
+    case MC_SR:
+        r = &s->bm_regs[GET_BM (index)];
+        val = r->sr & 0xff;
+        dolog ("SRb[%d] -> %#x\n", GET_BM (index), val);
+        break;
+    default:
+        dolog ("U nabm readb %#x -> %#x\n", addr, val);
+        break;
+    }
+    return val;
+}
+
+static uint32_t nabm_readw (void *opaque, uint32_t addr)
+{
+    PCIAC97LinkState *d = opaque;
+    AC97LinkState *s = &d->ac97;
+    AC97BusMasterRegs *r = NULL;
+    uint32_t index = addr - s->base[1];
+    uint32_t val = ~0U;
+
+    switch (index) {
+    case PI_SR:
+    case PO_SR:
+    case MC_SR:
+        r = &s->bm_regs[GET_BM (index)];
+        val = r->sr;
+        dolog ("SR[%d] -> %#x\n", GET_BM (index), val);
+        break;
+    case PI_PICB:
+    case PO_PICB:
+    case MC_PICB:
+        r = &s->bm_regs[GET_BM (index)];
+        val = r->picb;
+        dolog ("PICB[%d] -> %#x\n", GET_BM (index), val);
+        break;
+    default:
+        dolog ("U nabm readw %#x -> %#x\n", addr, val);
+        break;
+    }
+    return val;
+}
+
+static uint32_t nabm_readl (void *opaque, uint32_t addr)
+{
+    PCIAC97LinkState *d = opaque;
+    AC97LinkState *s = &d->ac97;
+    AC97BusMasterRegs *r = NULL;
+    uint32_t index = addr - s->base[1];
+    uint32_t val = ~0U;
+
+    switch (index) {
+    case PI_BDBAR:
+    case PO_BDBAR:
+    case MC_BDBAR:
+        r = &s->bm_regs[GET_BM (index)];
+        val = r->bdbar;
+        dolog ("BMADDR[%d] -> %#x\n", GET_BM (index), val);
+        break;
+    case PI_CIV:
+    case PO_CIV:
+    case MC_CIV:
+        r = &s->bm_regs[GET_BM (index)];
+        val = r->civ | (r->lvi << 8) | (r->sr << 16);
+        dolog ("CIV LVI SR[%d] -> %#x, %#x, %#x\n", GET_BM (index),
+               r->civ, r->lvi, r->sr);
+        break;
+    case PI_PICB:
+    case PO_PICB:
+    case MC_PICB:
+        r = &s->bm_regs[GET_BM (index)];
+        val = r->picb | (r->piv << 16) | (r->cr << 24);
+        dolog ("PICB PIV CR[%d] -> %#x %#x %#x %#x\n", GET_BM (index),
+               val, r->picb, r->piv, r->cr);
+        break;
+    case GLOB_CNT:
+        val = s->glob_cnt;
+        dolog ("glob_cnt -> %#x\n", val);
+        break;
+    case GLOB_STA:
+        val = s->glob_sta | GS_S0CR;
+        dolog ("glob_sta -> %#x\n", val);
+        break;
+    default:
+        dolog ("U nabm readl %#x -> %#x\n", addr, val);
+        break;
+    }
+    return val;
+}
+
+/**
+ * Native audio bus master
+ * I/O Writes
+ */
+static void nabm_writeb (void *opaque, uint32_t addr, uint32_t val)
+{
+    PCIAC97LinkState *d = opaque;
+    AC97LinkState *s = &d->ac97;
+    AC97BusMasterRegs *r = NULL;
+    uint32_t index = addr - s->base[1];
+    switch (index) {
+    case PI_LVI:
+    case PO_LVI:
+    case MC_LVI:
+        r = &s->bm_regs[GET_BM (index)];
+        if ((r->cr & CR_RPBM) && (r->sr & SR_DCH)) {
+            r->sr &= ~(SR_DCH | SR_CELV);
+            r->civ = r->piv;
+            r->piv = (r->piv + 1) % 32;
+            fetch_bd (s, r);
+        }
+        r->lvi = val % 32;
+        dolog ("LVI[%d] <- %#x\n", GET_BM (index), val);
+        break;
+    case PI_CR:
+    case PO_CR:
+    case MC_CR:
+        r = &s->bm_regs[GET_BM (index)];
+        if (val & CR_RR) {
+            reset_bm_regs (s, r);
+        }
+        else {
+            r->cr = val & CR_VALID_MASK;
+            if (!(r->cr & CR_RPBM)) {
+                voice_set_active (s, r - s->bm_regs, 0);
+                r->sr |= SR_DCH;
+            }
+            else {
+                r->civ = r->piv;
+                r->piv = (r->piv + 1) % 32;
+                fetch_bd (s, r);
+                r->sr &= ~SR_DCH;
+                voice_set_active (s, r - s->bm_regs, 1);
+            }
+        }
+        dolog ("CR[%d] <- %#x (cr %#x)\n", GET_BM (index), val, r->cr);
+        break;
+    case PI_SR:
+    case PO_SR:
+    case MC_SR:
+        r = &s->bm_regs[GET_BM (index)];
+        r->sr |= val & ~(SR_RO_MASK | SR_WCLEAR_MASK);
+        update_sr (s, r, r->sr & ~(val & SR_WCLEAR_MASK));
+        dolog ("SR[%d] <- %#x (sr %#x)\n", GET_BM (index), val, r->sr);
+        break;
+    default:
+        dolog ("U nabm writeb %#x <- %#x\n", addr, val);
+        break;
+    }
+}
+
+static void nabm_writew (void *opaque, uint32_t addr, uint32_t val)
+{
+    PCIAC97LinkState *d = opaque;
+    AC97LinkState *s = &d->ac97;
+    AC97BusMasterRegs *r = NULL;
+    uint32_t index = addr - s->base[1];
+    switch (index) {
+    case PI_SR:
+    case PO_SR:
+    case MC_SR:
+        r = &s->bm_regs[GET_BM (index)];
+        r->sr |= val & ~(SR_RO_MASK | SR_WCLEAR_MASK);
+        update_sr (s, r, r->sr & ~(val & SR_WCLEAR_MASK));
+        dolog ("SR[%d] <- %#x (sr %#x)\n", GET_BM (index), val, r->sr);
+        break;
+    default:
+        dolog ("U nabm writew %#x <- %#x\n", addr, val);
+        break;
+    }
+}
+
+static void nabm_writel (void *opaque, uint32_t addr, uint32_t val)
+{
+    PCIAC97LinkState *d = opaque;
+    AC97LinkState *s = &d->ac97;
+    AC97BusMasterRegs *r = NULL;
+    uint32_t index = addr - s->base[1];
+    switch (index) {
+    case PI_BDBAR:
+    case PO_BDBAR:
+    case MC_BDBAR:
+        r = &s->bm_regs[GET_BM (index)];
+        r->bdbar = val & ~3;
+        dolog ("BDBAR[%d] <- %#x (bdbar %#x)\n",
+               GET_BM (index), val, r->bdbar);
+        break;
+    case GLOB_CNT:
+        if (val & GC_WR)
+            warm_reset (s);
+        if (val & GC_CR)
+            cold_reset (s);
+        if (!(val & (GC_WR | GC_CR)))
+            s->glob_cnt = val & GC_VALID_MASK;
+        dolog ("glob_cnt <- %#x (glob_cnt %#x)\n", val, s->glob_cnt);
+        break;
+    case GLOB_STA:
+        s->glob_sta &= ~(val & GS_WCLEAR_MASK);
+        s->glob_sta |= (val & ~(GS_WCLEAR_MASK | GS_RO_MASK)) & GS_VALID_MASK;
+        dolog ("glob_sta <- %#x (glob_sta %#x)\n", val, s->glob_sta);
+        break;
+    default:
+        dolog ("U nabm writel %#x <- %#x\n", addr, val);
+        break;
+    }
+}
+
+static int write_audio (AC97LinkState *s, AC97BusMasterRegs *r,
+                        int max, int *stop)
+{
+    uint8_t tmpbuf[4096];
+    uint32_t addr = r->bd.addr;
+    uint32_t temp = r->picb << 1;
+    uint32_t written = 0;
+    int to_copy = 0;
+    temp = audio_MIN (temp, max);
+
+    if (!temp) {
+        *stop = 1;
+        return 0;
+    }
+
+    while (temp) {
+        int copied;
+        to_copy = audio_MIN (temp, sizeof (tmpbuf));
+        cpu_physical_memory_read (addr, tmpbuf, to_copy);
+        copied = AUD_write (s->voice_po, tmpbuf, to_copy);
+        dolog ("write_audio max=%x to_copy=%x copied=%x\n",
+               max, to_copy, copied);
+        if (!copied) {
+            *stop = 1;
+            break;
+        }
+        temp -= copied;
+        addr += copied;
+        written += copied;
+    }
+
+    if (!temp) {
+        if (to_copy < 4) {
+            dolog ("whoops\n");
+            s->last_samp = 0;
+        }
+        else {
+            s->last_samp = *(uint32_t *) &tmpbuf[to_copy - 4];
+        }
+    }
+
+    r->bd.addr = addr;
+    return written;
+}
+
+static void write_bup (AC97LinkState *s, int elapsed)
+{
+    int written = 0;
+
+    dolog ("write_bup\n");
+    if (!(s->bup_flag & BUP_SET)) {
+        if (s->bup_flag & BUP_LAST) {
+            int i;
+            uint8_t *p = s->silence;
+            for (i = 0; i < sizeof (s->silence) / 4; i++, p += 4) {
+                *(uint32_t *) p = s->last_samp;
+            }
+        }
+        else {
+            memset (s->silence, 0, sizeof (s->silence));
+        }
+        s->bup_flag |= BUP_SET;
+    }
+
+    while (elapsed) {
+        int temp = audio_MIN (elapsed, sizeof (s->silence));
+        while (temp) {
+            int copied = AUD_write (s->voice_po, s->silence, temp);
+            if (!copied)
+                return;
+            temp -= copied;
+            elapsed -= copied;
+            written += copied;
+        }
+    }
+}
+
+static int read_audio (AC97LinkState *s, AC97BusMasterRegs *r,
+                       int max, int *stop)
+{
+    uint8_t tmpbuf[4096];
+    uint32_t addr = r->bd.addr;
+    uint32_t temp = r->picb << 1;
+    uint32_t nread = 0;
+    int to_copy = 0;
+    SWVoiceIn *voice = (r - s->bm_regs) == MC_INDEX ? s->voice_mc : s->voice_pi;
+
+    temp = audio_MIN (temp, max);
+
+    if (!temp) {
+        *stop = 1;
+        return 0;
+    }
+
+    while (temp) {
+        int acquired;
+        to_copy = audio_MIN (temp, sizeof (tmpbuf));
+        acquired = AUD_read (voice, tmpbuf, to_copy);
+        if (!acquired) {
+            *stop = 1;
+            break;
+        }
+        cpu_physical_memory_write (addr, tmpbuf, acquired);
+        temp -= acquired;
+        addr += acquired;
+        nread += acquired;
+    }
+
+    r->bd.addr = addr;
+    return nread;
+}
+
+static void transfer_audio (AC97LinkState *s, int index, int elapsed)
+{
+    AC97BusMasterRegs *r = &s->bm_regs[index];
+    int written = 0, stop = 0;
+
+    if (r->sr & SR_DCH) {
+        if (r->cr & CR_RPBM) {
+            switch (index) {
+            case PO_INDEX:
+                write_bup (s, elapsed);
+                break;
+            }
+        }
+        return;
+    }
+
+    while ((elapsed >> 1) && !stop) {
+        int temp;
+
+        if (!r->bd_valid) {
+            dolog ("invalid bd\n");
+            fetch_bd (s, r);
+        }
+
+        if (!r->picb) {
+            dolog ("fresh bd %d is empty %#x %#x\n",
+                   r->civ, r->bd.addr, r->bd.ctl_len);
+            if (r->civ == r->lvi) {
+                r->sr |= SR_DCH; /* CELV? */
+                s->bup_flag = 0;
+                break;
+            }
+            r->sr &= ~SR_CELV;
+            r->civ = r->piv;
+            r->piv = (r->piv + 1) % 32;
+            fetch_bd (s, r);
+            return;
+        }
+
+        switch (index) {
+        case PO_INDEX:
+            temp = write_audio (s, r, elapsed, &stop);
+            written += temp;
+            elapsed -= temp;
+            r->picb -= (temp >> 1);
+            break;
+
+        case PI_INDEX:
+        case MC_INDEX:
+            temp = read_audio (s, r, elapsed, &stop);
+            elapsed -= temp;
+            r->picb -= (temp >> 1);
+            break;
+        }
+
+        if (!r->picb) {
+            uint32_t new_sr = r->sr & ~SR_CELV;
+
+            if (r->bd.ctl_len & BD_IOC) {
+                new_sr |= SR_BCIS;
+            }
+
+            if (r->civ == r->lvi) {
+                dolog ("Underrun civ (%d) == lvi (%d)\n", r->civ, r->lvi);
+
+                new_sr |= SR_LVBCI | SR_DCH | SR_CELV;
+                stop = 1;
+                s->bup_flag = (r->bd.ctl_len & BD_BUP) ? BUP_LAST : 0;
+            }
+            else {
+                r->civ = r->piv;
+                r->piv = (r->piv + 1) % 32;
+                fetch_bd (s, r);
+            }
+
+            update_sr (s, r, new_sr);
+        }
+    }
+}
+
+static void pi_callback (void *opaque, int avail)
+{
+    transfer_audio (opaque, PI_INDEX, avail);
+}
+
+static void mc_callback (void *opaque, int avail)
+{
+    transfer_audio (opaque, MC_INDEX, avail);
+}
+
+static void po_callback (void *opaque, int free)
+{
+    transfer_audio (opaque, PO_INDEX, free);
+}
+
+static void ac97_save (QEMUFile *f, void *opaque)
+{
+    size_t i;
+    uint8_t active[LAST_INDEX];
+    AC97LinkState *s = opaque;
+
+    qemu_put_be32s (f, &s->glob_cnt);
+    qemu_put_be32s (f, &s->glob_sta);
+    qemu_put_be32s (f, &s->cas);
+
+    for (i = 0; i < sizeof (s->bm_regs) / sizeof (s->bm_regs[0]); ++i) {
+        AC97BusMasterRegs *r = &s->bm_regs[i];
+        qemu_put_be32s (f, &r->bdbar);
+        qemu_put_8s (f, &r->civ);
+        qemu_put_8s (f, &r->lvi);
+        qemu_put_be16s (f, &r->sr);
+        qemu_put_be16s (f, &r->picb);
+        qemu_put_8s (f, &r->piv);
+        qemu_put_8s (f, &r->cr);
+        qemu_put_be32s (f, &r->bd_valid);
+        qemu_put_be32s (f, &r->bd.addr);
+        qemu_put_be32s (f, &r->bd.ctl_len);
+    }
+    qemu_put_buffer (f, s->mixer_data, sizeof (s->mixer_data));
+
+    active[PI_INDEX] = AUD_is_active_in (s->voice_pi) ? 1 : 0;
+    active[PO_INDEX] = AUD_is_active_out (s->voice_po) ? 1 : 0;
+    active[MC_INDEX] = AUD_is_active_in (s->voice_mc) ? 1 : 0;
+    qemu_put_buffer (f, active, sizeof (active));
+}
+
+static int ac97_load (QEMUFile *f, void *opaque, int version_id)
+{
+    size_t i;
+    uint8_t active[LAST_INDEX];
+    AC97LinkState *s = opaque;
+
+    if (version_id != 1)
+        return -EINVAL;
+
+    qemu_get_be32s (f, &s->glob_cnt);
+    qemu_get_be32s (f, &s->glob_sta);
+    qemu_get_be32s (f, &s->cas);
+
+    for (i = 0; i < sizeof (s->bm_regs) / sizeof (s->bm_regs[0]); ++i) {
+        AC97BusMasterRegs *r = &s->bm_regs[i];
+        qemu_get_be32s (f, &r->bdbar);
+        qemu_get_8s (f, &r->civ);
+        qemu_get_8s (f, &r->lvi);
+        qemu_get_be16s (f, &r->sr);
+        qemu_get_be16s (f, &r->picb);
+        qemu_get_8s (f, &r->piv);
+        qemu_get_8s (f, &r->cr);
+        qemu_get_be32s (f, &r->bd_valid);
+        qemu_get_be32s (f, &r->bd.addr);
+        qemu_get_be32s (f, &r->bd.ctl_len);
+    }
+    qemu_get_buffer (f, s->mixer_data, sizeof (s->mixer_data));
+    qemu_get_buffer (f, active, sizeof (active));
+
+#ifdef USE_MIXER
+    record_select (s, mixer_load (s, AC97_Record_Select));
+#define V_(a, b) set_volume (s, a, b, mixer_load (s, a))
+    V_ (AC97_Master_Volume_Mute, AUD_MIXER_VOLUME);
+    V_ (AC97_PCM_Out_Volume_Mute, AUD_MIXER_PCM);
+    V_ (AC97_Line_In_Volume_Mute, AUD_MIXER_LINE_IN);
+#undef V_
+#endif
+    reset_voices (s, active);
+
+    s->bup_flag = 0;
+    s->last_samp = 0;
+    return 0;
+}
+
+static void ac97_map (PCIDevice *pci_dev, int region_num,
+                      uint32_t addr, uint32_t size, int type)
+{
+    PCIAC97LinkState *d = (PCIAC97LinkState *) pci_dev;
+    AC97LinkState *s = &d->ac97;
+
+    if (!region_num) {
+        s->base[0] = addr;
+        register_ioport_read (addr, 256 * 1, 1, nam_readb, d);
+        register_ioport_read (addr, 256 * 2, 2, nam_readw, d);
+        register_ioport_read (addr, 256 * 4, 4, nam_readl, d);
+        register_ioport_write (addr, 256 * 1, 1, nam_writeb, d);
+        register_ioport_write (addr, 256 * 2, 2, nam_writew, d);
+        register_ioport_write (addr, 256 * 4, 4, nam_writel, d);
+    }
+    else {
+        s->base[1] = addr;
+        register_ioport_read (addr, 64 * 1, 1, nabm_readb, d);
+        register_ioport_read (addr, 64 * 2, 2, nabm_readw, d);
+        register_ioport_read (addr, 64 * 4, 4, nabm_readl, d);
+        register_ioport_write (addr, 64 * 1, 1, nabm_writeb, d);
+        register_ioport_write (addr, 64 * 2, 2, nabm_writew, d);
+        register_ioport_write (addr, 64 * 4, 4, nabm_writel, d);
+    }
+}
+
+static void ac97_on_reset (void *opaque)
+{
+    AC97LinkState *s = opaque;
+
+    reset_bm_regs (s, &s->bm_regs[0]);
+    reset_bm_regs (s, &s->bm_regs[1]);
+    reset_bm_regs (s, &s->bm_regs[2]);
+
+    /*
+     * Reset the mixer too. The Windows XP driver seems to rely on
+     * this. At least it wants to read the vendor id before it resets
+     * the codec manually.
+     */
+    mixer_reset (s);
+}
+
+int ac97_init (PCIBus *bus, AudioState *audio)
+{
+    PCIAC97LinkState *d;
+    AC97LinkState *s;
+    uint8_t *c;
+
+    if (!bus) {
+        AUD_log ("ac97", "No PCI bus\n");
+        return -1;
+    }
+
+    if (!audio) {
+        AUD_log ("ac97", "No audio state\n");
+        return -1;
+    }
+
+    d = (PCIAC97LinkState *) pci_register_device (bus, "AC97",
+                                                  sizeof (PCIAC97LinkState),
+                                                  -1, NULL, NULL);
+
+    if (!d) {
+        AUD_log ("ac97", "Failed to register PCI device\n");
+        return -1;
+    }
+
+    s = &d->ac97;
+    s->pci_dev = &d->dev;
+    c = d->dev.config;
+    c[0x00] = 0x86;      /* vid vendor id intel ro */
+    c[0x01] = 0x80;      /* intel */
+
+    c[0x02] = 0x15;      /* did device id 82801 ro */
+    c[0x03] = 0x24;      /* 82801aa */
+
+    c[0x04] = 0x00;      /* pcicmd pci command rw, ro */
+    c[0x05] = 0x00;
+
+    c[0x06] = 0x80;      /* pcists pci status rwc, ro */
+    c[0x07] = 0x02;
+
+    c[0x08] = 0x01;      /* rid revision ro */
+    c[0x09] = 0x00;      /* pi programming interface ro */
+    c[0x0a] = 0x01;      /* scc sub class code ro */
+    c[0x0b] = 0x04;      /* bcc base class code ro */
+    c[0x0e] = 0x00;      /* headtyp header type ro */
+
+    c[0x10] = 0x01;      /* nabmar native audio mixer base
+                            address rw */
+    c[0x11] = 0x00;
+    c[0x12] = 0x00;
+    c[0x13] = 0x00;
+
+    c[0x14] = 0x01;      /* nabmbar native audio bus mastering
+                            base address rw */
+    c[0x15] = 0x00;
+    c[0x16] = 0x00;
+    c[0x17] = 0x00;
+
+    c[0x2c] = 0x86;      /* svid subsystem vendor id rwo */
+    c[0x2d] = 0x80;
+
+    c[0x2e] = 0x00;      /* sid subsystem id rwo */
+    c[0x2f] = 0x00;
+
+    c[0x3c] = 0x00;      /* intr_ln interrupt line rw */
+    c[0x3d] = 0x01;      /* intr_pn interrupt pin ro */
+
+    pci_register_io_region (&d->dev, 0, 256 * 4, PCI_ADDRESS_SPACE_IO, ac97_map);
+    pci_register_io_region (&d->dev, 1, 64 * 4, PCI_ADDRESS_SPACE_IO, ac97_map);
+    register_savevm ("ac97", 0, 1, ac97_save, ac97_load, s);
+    qemu_register_reset (ac97_on_reset, s);
+    AUD_register_card (audio, "ac97", &s->card);
+    ac97_on_reset (s);
+    return 0;
+}

Modified: trunk/src/host/qemu-neo1973/hw/acpi.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/acpi.c	2008-01-14 20:40:58 UTC (rev 3831)
+++ trunk/src/host/qemu-neo1973/hw/acpi.c	2008-01-14 23:24:21 UTC (rev 3832)
@@ -482,7 +482,7 @@
     pci_conf[0x03] = 0x71;
     pci_conf[0x06] = 0x80;
     pci_conf[0x07] = 0x02;
-    pci_conf[0x08] = 0x00; // revision number
+    pci_conf[0x08] = 0x03; // revision number
     pci_conf[0x09] = 0x00;
     pci_conf[0x0a] = 0x80; // other bridge device
     pci_conf[0x0b] = 0x06; // bridge device

Modified: trunk/src/host/qemu-neo1973/hw/audiodev.h
===================================================================
--- trunk/src/host/qemu-neo1973/hw/audiodev.h	2008-01-14 20:40:58 UTC (rev 3831)
+++ trunk/src/host/qemu-neo1973/hw/audiodev.h	2008-01-14 23:24:21 UTC (rev 3832)
@@ -10,3 +10,5 @@
 /* gus.c */
 int GUS_init (AudioState *s, qemu_irq *pic);
 
+/* ac97.c */
+int ac97_init (PCIBus *buf, AudioState *s);

Modified: trunk/src/host/qemu-neo1973/hw/dma.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/dma.c	2008-01-14 20:40:58 UTC (rev 3831)
+++ trunk/src/host/qemu-neo1973/hw/dma.c	2008-01-14 23:24:21 UTC (rev 3832)
@@ -439,6 +439,13 @@
     write_cont (d, (0x0d << d->dshift), 0);
 }
 
+static int dma_phony_handler (void *opaque, int nchan, int dma_pos, int dma_len)
+{
+    dolog ("unregistered DMA channel used nchan=%d dma_pos=%d dma_len=%d\n",
+           nchan, dma_pos, dma_len);
+    return dma_pos;
+}
+
 /* dshift = 0: 8 bit DMA, 1 = 16 bit DMA */
 static void dma_init2(struct dma_cont *d, int base, int dshift,
                       int page_base, int pageh_base)
@@ -471,6 +478,9 @@
     }
     qemu_register_reset(dma_reset, d);
     dma_reset(d);
+    for (i = 0; i < LENOFA (d->regs); ++i) {
+        d->regs[i].transfer_handler = dma_phony_handler;
+    }
 }
 
 static void dma_save (QEMUFile *f, void *opaque)

Added: trunk/src/host/qemu-neo1973/hw/gus.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/gus.c	2008-01-14 20:40:58 UTC (rev 3831)
+++ trunk/src/host/qemu-neo1973/hw/gus.c	2008-01-14 23:24:21 UTC (rev 3832)
@@ -0,0 +1,300 @@
+/*
+ * QEMU Proxy for Gravis Ultrasound GF1 emulation by Tibor "TS" Schütz
+ *
+ * Copyright (c) 2002-2005 Vassili Karpov (malc)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "hw.h"
+#include "audiodev.h"
+#include "audio/audio.h"
+#include "isa.h"
+#include "gusemu.h"
+#include "gustate.h"
+
+#define dolog(...) AUD_log ("audio", __VA_ARGS__)
+#ifdef DEBUG
+#define ldebug(...) dolog (__VA_ARGS__)
+#else
+#define ldebug(...)
+#endif
+
+#ifdef WORDS_BIGENDIAN
+#define GUS_ENDIANNESS 1
+#else
+#define GUS_ENDIANNESS 0
+#endif
+
+#define IO_READ_PROTO(name) \
+    uint32_t name (void *opaque, uint32_t nport)
+#define IO_WRITE_PROTO(name) \
+    void name (void *opaque, uint32_t nport, uint32_t val)
+
+static struct {
+    int port;
+    int irq;
+    int dma;
+    int freq;
+} conf = {0x240, 7, 3, 44100};
+
+typedef struct GUSState {
+    GUSEmuState emu;
+    QEMUSoundCard card;
+    int freq;
+    int pos, left, shift, irqs;
+    uint16_t *mixbuf;
+    uint8_t himem[1024 * 1024 + 32 + 4096];
+    int samples;
+    SWVoiceOut *voice;
+    int64_t last_ticks;
+    qemu_irq *pic;
+} GUSState;
+
+IO_READ_PROTO (gus_readb)
+{
+    GUSState *s = opaque;
+
+    return gus_read (&s->emu, nport, 1);
+}
+
+IO_READ_PROTO (gus_readw)
+{
+    GUSState *s = opaque;
+
+    return gus_read (&s->emu, nport, 2);
+}
+
+IO_WRITE_PROTO (gus_writeb)
+{
+    GUSState *s = opaque;
+
+    gus_write (&s->emu, nport, 1, val);
+}
+
+IO_WRITE_PROTO (gus_writew)
+{
+    GUSState *s = opaque;
+
+    gus_write (&s->emu, nport, 2, val);
+}
+
+static int write_audio (GUSState *s, int samples)
+{
+    int net = 0;
+    int pos = s->pos;
+
+    while (samples) {
+        int nbytes, wbytes, wsampl;
+
+        nbytes = samples << s->shift;
+        wbytes = AUD_write (
+            s->voice,
+            s->mixbuf + (pos << (s->shift - 1)),
+            nbytes
+            );
+
+        if (wbytes) {
+            wsampl = wbytes >> s->shift;
+
+            samples -= wsampl;
+            pos = (pos + wsampl) % s->samples;
+
+            net += wsampl;
+        }
+        else {
+            break;
+        }
+    }
+
+    return net;
+}
+
+static void GUS_callback (void *opaque, int free)
+{
+    int samples, to_play, net = 0;
+    GUSState *s = opaque;
+
+    samples = free >> s->shift;
+    to_play = audio_MIN (samples, s->left);
+
+    while (to_play) {
+        int written = write_audio (s, to_play);
+
+        if (!written) {
+            goto reset;
+        }
+
+        s->left -= written;
+        to_play -= written;
+        samples -= written;
+        net += written;
+    }
+
+    samples = audio_MIN (samples, s->samples);
+    if (samples) {
+        gus_mixvoices (&s->emu, s->freq, samples, s->mixbuf);
+
+        while (samples) {
+            int written = write_audio (s, samples);
+            if (!written) {
+                break;
+            }
+            samples -= written;
+            net += written;
+        }
+    }
+    s->left = samples;
+
+reset:
+    gus_irqgen (&s->emu, (double) (net * 1000000) / s->freq);
+}
+
+int GUS_irqrequest (GUSEmuState *emu, int hwirq, int n)
+{
+    GUSState *s = emu->opaque;
+    /* qemu_irq_lower (s->pic[hwirq]); */
+    qemu_irq_raise (s->pic[hwirq]);
+    s->irqs += n;
+    ldebug ("irqrequest %d %d %d\n", hwirq, n, s->irqs);
+    return n;
+}
+
+void GUS_irqclear (GUSEmuState *emu, int hwirq)
+{
+    GUSState *s = emu->opaque;
+    ldebug ("irqclear %d %d\n", hwirq, s->irqs);
+    qemu_irq_lower (s->pic[hwirq]);
+    s->irqs -= 1;
+#ifdef IRQ_STORM
+    if (s->irqs > 0) {
+        qemu_irq_raise (s->pic[hwirq]);
+    }
+#endif
+}
+
+void GUS_dmarequest (GUSEmuState *der)
+{
+    /* GUSState *s = (GUSState *) der; */
+    ldebug ("dma request %d\n", der->gusdma);
+    DMA_hold_DREQ (der->gusdma);
+}
+
+int GUS_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len)
+{
+    GUSState *s = opaque;
+    int8_t tmpbuf[4096];
+    int pos = dma_pos, mode, left = dma_len - dma_pos;
+
+    ldebug ("read DMA %#x %d\n", dma_pos, dma_len);
+    mode = DMA_get_channel_mode (s->emu.gusdma);
+    while (left) {
+        int to_copy = audio_MIN ((size_t) left, sizeof (tmpbuf));
+        int copied;
+
+        ldebug ("left=%d to_copy=%d pos=%d\n", left, to_copy, pos);
+        copied = DMA_read_memory (nchan, tmpbuf, pos, to_copy);
+        gus_dma_transferdata (&s->emu, tmpbuf, copied, left == copied);
+        left -= copied;
+        pos += copied;
+    }
+
+    if (0 == ((mode >> 4) & 1)) {
+        DMA_release_DREQ (s->emu.gusdma);
+    }
+    return dma_len;
+}
+
+int GUS_init (AudioState *audio, qemu_irq *pic)
+{
+    GUSState *s;
+    audsettings_t as;
+
+    if (!audio) {
+        dolog ("No audio state\n");
+        return -1;
+    }
+
+    s = qemu_mallocz (sizeof (*s));
+    if (!s) {
+        dolog ("Could not allocate memory for GUS (%zu bytes)\n",
+               sizeof (*s));
+        return -1;
+    }
+
+    AUD_register_card (audio, "gus", &s->card);
+
+    as.freq = conf.freq;
+    as.nchannels = 2;
+    as.fmt = AUD_FMT_S16;
+    as.endianness = GUS_ENDIANNESS;
+
+    s->voice = AUD_open_out (
+        &s->card,
+        NULL,
+        "gus",
+        s,
+        GUS_callback,
+        &as
+        );
+
+    if (!s->voice) {
+        AUD_remove_card (&s->card);
+        qemu_free (s);
+        return -1;
+    }
+
+    s->shift = 2;
+    s->samples = AUD_get_buffer_size_out (s->voice) >> s->shift;
+    s->mixbuf = qemu_mallocz (s->samples << s->shift);
+    if (!s->mixbuf) {
+        AUD_close_out (&s->card, s->voice);
+        AUD_remove_card (&s->card);
+        qemu_free (s);
+        return -1;
+    }
+
+    register_ioport_write (conf.port, 1, 1, gus_writeb, s);
+    register_ioport_write (conf.port, 1, 2, gus_writew, s);
+
+    register_ioport_read ((conf.port + 0x100) & 0xf00, 1, 1, gus_readb, s);
+    register_ioport_read ((conf.port + 0x100) & 0xf00, 1, 2, gus_readw, s);
+
+    register_ioport_write (conf.port + 6, 10, 1, gus_writeb, s);
+    register_ioport_write (conf.port + 6, 10, 2, gus_writew, s);
+    register_ioport_read (conf.port + 6, 10, 1, gus_readb, s);
+    register_ioport_read (conf.port + 6, 10, 2, gus_readw, s);
+
+
+    register_ioport_write (conf.port + 0x100, 8, 1, gus_writeb, s);
+    register_ioport_write (conf.port + 0x100, 8, 2, gus_writew, s);
+    register_ioport_read (conf.port + 0x100, 8, 1, gus_readb, s);
+    register_ioport_read (conf.port + 0x100, 8, 2, gus_readw, s);
+
+    DMA_register_channel (conf.dma, GUS_read_DMA, s);
+    s->emu.gusirq = conf.irq;
+    s->emu.gusdma = conf.dma;
+    s->emu.himemaddr = s->himem;
+    s->emu.gusdatapos = s->emu.himemaddr + 1024 * 1024 + 32;
+    s->emu.opaque = s;
+    s->freq = conf.freq;
+    s->pic = pic;
+
+    AUD_set_active_out (s->voice, 1);
+    return 0;
+}

Added: trunk/src/host/qemu-neo1973/hw/gusemu.h
===================================================================
--- trunk/src/host/qemu-neo1973/hw/gusemu.h	2008-01-14 20:40:58 UTC (rev 3831)
+++ trunk/src/host/qemu-neo1973/hw/gusemu.h	2008-01-14 23:24:21 UTC (rev 3832)
@@ -0,0 +1,103 @@
+/*
+ * GUSEMU32 - API
+ *
+ * Copyright (C) 2000-2007 Tibor "TS" Schütz
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef GUSEMU_H
+#define GUSEMU_H
+
+/* data types (need to be adjusted if neither a VC6 nor a C99 compatible compiler is used) */
+
+#if defined _WIN32 && defined _MSC_VER /* doesnt support other win32 compilers yet, do it yourself... */
+ typedef unsigned char GUSbyte;
+ typedef unsigned short GUSword;
+ typedef unsigned int GUSdword;
+ typedef signed char GUSchar;
+#else
+ #include <stdint.h>
+ typedef int8_t GUSchar;
+ typedef uint8_t GUSbyte;
+ typedef uint16_t GUSword;
+ typedef uint32_t GUSdword;
+#endif
+
+typedef struct _GUSEmuState
+{
+ GUSbyte *himemaddr; /* 1024*1024 bytes used for storing uploaded samples (+32 additional bytes for read padding) */
+ GUSbyte *gusdatapos; /* (gusdataend-gusdata) bytes used for storing emulated GF1/mixer register states (32*32+4 bytes in initial GUSemu32 version) */
+ int gusirq;
+ int gusdma;
+ unsigned int timer1fraction;
+ unsigned int timer2fraction;
+ void *opaque;
+} GUSEmuState;
+
+/* ** Callback functions needed: */
+/* NMI is defined as hwirq=-1 (not supported (yet?)) */
+/* GUS_irqrequest returns the number of IRQs actually scheduled into the virtual machine */
+/* Level triggered IRQ simulations normally return 1 */
+/* Event triggered IRQ simulation can safely ignore GUS_irqclear calls */
+int  GUS_irqrequest(GUSEmuState *state, int hwirq, int num);/* needed in both mixer and bus emulation functions. */
+void GUS_irqclear(  GUSEmuState *state, int hwirq); /* used by gus_write() only - can be left empty for mixer functions */
+void GUS_dmarequest(GUSEmuState *state);            /* used by gus_write() only - can be left empty for mixer functions */
+
+/* ** ISA bus interface functions: */
+
+/* Port I/O handlers */
+/* support the following ports: */
+/* 2x0,2x6,2x8...2xF,3x0...3x7;  */
+/* optional: 388,389 (at least writes should be forwarded or some GUS detection algorithms will fail) */
+/* data is passed in host byte order */
+unsigned int gus_read( GUSEmuState *state, int port, int size);
+void         gus_write(GUSEmuState *state, int port, int size, unsigned int data);
+/* size is given in bytes (1 for byte, 2 for word) */
+
+/* DMA data transfer function */
+/* data pointed to is passed in native x86 order */
+void gus_dma_transferdata(GUSEmuState *state, char *dma_addr, unsigned int count, int TC);
+/* Called back by GUS_start_DMA as soon as the emulated DMA controller is ready for a transfer to or from GUS */
+/* (might be immediately if the DMA controller was programmed first) */
+/* dma_addr is an already translated address directly pointing to the beginning of the memory block */
+/* do not forget to update DMA states after the call, including the DREQ and TC flags */
+/* it is possible to break down a single transfer into multiple ones, but take care that: */
+/* -dma_count is actually count-1 */
+/* -before and during a transfer, DREQ is set and TC cleared */
+/* -when calling gus_dma_transferdata(), TC is only set true for call transfering the last byte */
+/* -after the last transfer, DREQ is cleared and TC is set */
+
+/* ** GF1 mixer emulation functions: */
+/* Usually, gus_irqgen should be called directly after gus_mixvoices if you can meet the recommended ranges. */
+/* If the interrupts are executed immediately (i.e., are synchronous), it may be useful to break this */
+/* down into a sequence of gus_mixvoice();gus_irqgen(); calls while mixing an audio block. */
+/* If the interrupts are asynchronous, it may be needed to use a separate thread mixing into a temporary */
+/* audio buffer in order to avoid quality loss caused by large numsamples and elapsed_time values. */
+
+void gus_mixvoices(GUSEmuState *state, unsigned int playback_freq, unsigned int numsamples, short *bufferpos);
+/* recommended range: 10 < numsamples < 100 */
+/* lower values may result in increased rounding error, higher values often cause audible timing delays */
+
+void gus_irqgen(GUSEmuState *state, unsigned int elapsed_time);
+/* recommended range: 80us < elapsed_time < max(1000us, numsamples/playback_freq) */
+/* lower values won´t provide any benefit at all, higher values can cause audible timing delays */
+/* note: masked timers are also calculated by this function, thus it might be needed even without any IRQs in use! */
+
+#endif  /* gusemu.h */

Added: trunk/src/host/qemu-neo1973/hw/gusemu_hal.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/gusemu_hal.c	2008-01-14 20:40:58 UTC (rev 3831)
+++ trunk/src/host/qemu-neo1973/hw/gusemu_hal.c	2008-01-14 23:24:21 UTC (rev 3832)
@@ -0,0 +1,554 @@
+/*
+ * GUSEMU32 - bus interface part
+ *
+ * Copyright (C) 2000-2007 Tibor "TS" Schütz
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/*
+ * TODO: check mixer: see 7.20 of sdk for panning pos (applies to all gus models?)?
+ */
+
+#include "gustate.h"
+#include "gusemu.h"
+
+#define GUSregb(position) (*            (gusptr+(position)))
+#define GUSregw(position) (*(GUSword *) (gusptr+(position)))
+#define GUSregd(position) (*(GUSdword *)(gusptr+(position)))
+
+/* size given in bytes */
+unsigned int gus_read(GUSEmuState * state, int port, int size)
+{
+    int             value_read = 0;
+
+    GUSbyte        *gusptr;
+    gusptr = state->gusdatapos;
+    GUSregd(portaccesses)++;
+
+    switch (port & 0xff0f)
+    {
+        /* MixerCtrlReg (read not supported on GUS classic) */
+        /* case 0x200: return GUSregb(MixerCtrlReg2x0); */
+    case 0x206:                          /* IRQstatReg / SB2x6IRQ */
+        /* adlib/sb bits set in port handlers */
+        /* timer/voice bits set in gus_irqgen() */
+        /* dma bit set in gus_dma_transferdata */
+        /* midi not implemented yet */
+        return GUSregb(IRQStatReg2x6);
+    /* case 0x308:                       */ /* AdLib388 */
+    case 0x208:
+        if (GUSregb(GUS45TimerCtrl) & 1)
+            return GUSregb(TimerStatus2x8);
+        return GUSregb(AdLibStatus2x8);  /* AdLibStatus */
+    case 0x309:                          /* AdLib389 */
+    case 0x209:
+        return GUSregb(AdLibData2x9);    /* AdLibData */
+    case 0x20A:
+        return GUSregb(AdLibCommand2xA); /* AdLib2x8_2xA */
+
+#if 0
+    case 0x20B:                          /* GUS hidden registers (read not supported on GUS classic) */
+        switch (GUSregb(RegCtrl_2xF) & 0x07)
+        {
+        case 0:                                 /* IRQ/DMA select */
+            if (GUSregb(MixerCtrlReg2x0) & 0x40)
+                return GUSregb(IRQ_2xB);        /* control register select bit */
+            else
+                return GUSregb(DMA_2xB);
+            /* case 1-5:                        */ /* general purpose emulation regs  */
+            /*  return ...                      */ /* + status reset reg (write only) */
+        case 6:
+            return GUSregb(Jumper_2xB);         /* Joystick/MIDI enable (JumperReg) */
+        default:;
+        }
+        break;
+#endif
+
+    case 0x20C:                          /* SB2xCd */
+        value_read = GUSregb(SB2xCd);
+        if (GUSregb(StatRead_2xF) & 0x20)
+            GUSregb(SB2xCd) ^= 0x80; /* toggle MSB on read */
+        return value_read;
+        /* case 0x20D:                   */ /* SB2xD is write only -> 2xE writes to it*/
+    case 0x20E:
+        if (GUSregb(RegCtrl_2xF) & 0x80) /* 2xE read IRQ enabled? */
+        {
+            GUSregb(StatRead_2xF) |= 0x80;
+            GUS_irqrequest(state, state->gusirq, 1);
+        }
+        return GUSregb(SB2xE);           /* SB2xE */
+    case 0x20F:                          /* StatRead_2xF */
+        /*set/clear fixed bits */
+        /*value_read = (GUSregb(StatRead_2xF) & 0xf9)|1; */ /*(LSB not set on GUS classic!)*/
+        value_read = (GUSregb(StatRead_2xF) & 0xf9);
+        if (GUSregb(MixerCtrlReg2x0) & 0x08)
+            value_read |= 2;    /* DMA/IRQ enabled flag */
+        return value_read;
+    /* case 0x300:                      */ /* MIDI (not implemented) */
+    /* case 0x301:                      */ /* MIDI (not implemented) */
+    case 0x302:
+        return GUSregb(VoiceSelReg3x2); /* VoiceSelReg */
+    case 0x303:
+        return GUSregb(FunkSelReg3x3);  /* FunkSelReg */
+    case 0x304:                         /* DataRegLoByte3x4 + DataRegWord3x4 */
+    case 0x305:                         /* DataRegHiByte3x5 */
+        switch (GUSregb(FunkSelReg3x3))
+        {
+    /* common functions */
+        case 0x41:                      /* DramDMAContrReg */
+            value_read = GUSregb(GUS41DMACtrl); /* &0xfb */
+            GUSregb(GUS41DMACtrl) &= 0xbb;
+            if (state->gusdma >= 4)
+                value_read |= 0x04;
+            if (GUSregb(IRQStatReg2x6) & 0x80)
+            {
+                value_read |= 0x40;
+                GUSregb(IRQStatReg2x6) &= 0x7f;
+                if (!GUSregb(IRQStatReg2x6))
+                    GUS_irqclear(state, state->gusirq);
+            }
+            return (GUSbyte) value_read;
+            /* DramDMAmemPosReg */
+            /* case 0x42: value_read=GUSregw(GUS42DMAStart); break;*/
+            /* 43h+44h write only */
+        case 0x45:
+            return GUSregb(GUS45TimerCtrl);         /* TimerCtrlReg */
+            /* 46h+47h write only */
+            /* 48h: samp freq - write only */
+        case 0x49:
+            return GUSregb(GUS49SampCtrl) & 0xbf;   /* SampCtrlReg */
+        /* case 4bh:                                */ /* joystick trim not supported */
+        /* case 0x4c: return GUSregb(GUS4cReset);   */ /* GUSreset: write only*/
+    /* voice specific functions */
+        case 0x80:
+        case 0x81:
+        case 0x82:
+        case 0x83:
+        case 0x84:
+        case 0x85:
+        case 0x86:
+        case 0x87:
+        case 0x88:
+        case 0x89:
+        case 0x8a:
+        case 0x8b:
+        case 0x8c:
+        case 0x8d:
+            {
+                int             offset = 2 * (GUSregb(FunkSelReg3x3) & 0x0f);
+                offset += ((int) GUSregb(VoiceSelReg3x2) & 0x1f) << 5; /* = Voice*32 + Funktion*2 */
+                value_read = GUSregw(offset);
+            }
+            break;
+    /* voice unspecific functions */
+        case 0x8e:                                  /* NumVoice */
+            return GUSregb(NumVoices);
+        case 0x8f:                                  /* irqstatreg */
+            /* (pseudo IRQ-FIFO is processed during a gus_write(0x3X3,0x8f)) */
+            return GUSregb(SynVoiceIRQ8f);
+        default:
+            return 0xffff;
+        }
+        if (size == 1)
+        {
+            if ((port & 0xff0f) == 0x305)
+                value_read = value_read >> 8;
+            value_read &= 0xff;
+        }
+        return (GUSword) value_read;
+    /* case 0x306:                                  */ /* Mixer/Version info */
+        /*  return 0xff; */ /* Pre 3.6 boards, ICS mixer NOT present */
+    case 0x307:                                     /* DRAMaccess */
+        {
+            GUSbyte        *adr;
+            adr = state->himemaddr + (GUSregd(GUSDRAMPOS24bit) & 0xfffff);
+            return *adr;
+        }
+    default:;
+    }
+    return 0xffff;
+}
+
+void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
+{
+    GUSbyte        *gusptr;
+    gusptr = state->gusdatapos;
+    GUSregd(portaccesses)++;
+
+    switch (port & 0xff0f)
+    {
+    case 0x200:                 /* MixerCtrlReg */
+        GUSregb(MixerCtrlReg2x0) = (GUSbyte) data;
+        break;
+    case 0x206:                 /* IRQstatReg / SB2x6IRQ */
+        if (GUSregb(GUS45TimerCtrl) & 0x20) /* SB IRQ enabled? -> set 2x6IRQ bit */
+        {
+            GUSregb(TimerStatus2x8) |= 0x08;
+            GUSregb(IRQStatReg2x6) = 0x10;
+            GUS_irqrequest(state, state->gusirq, 1);
+        }
+        break;
+    case 0x308:                /* AdLib 388h */
+    case 0x208:                /* AdLibCommandReg */
+        GUSregb(AdLibCommand2xA) = (GUSbyte) data;
+        break;
+    case 0x309:                /* AdLib 389h */
+    case 0x209:                /* AdLibDataReg */
+        if ((GUSregb(AdLibCommand2xA) == 0x04) && (!(GUSregb(GUS45TimerCtrl) & 1))) /* GUS auto timer mode enabled? */
+        {
+            if (data & 0x80)
+                GUSregb(TimerStatus2x8) &= 0x1f; /* AdLib IRQ reset? -> clear maskable adl. timer int regs */
+            else
+                GUSregb(TimerDataReg2x9) = (GUSbyte) data;
+        }
+        else
+        {
+            GUSregb(AdLibData2x9) = (GUSbyte) data;
+            if (GUSregb(GUS45TimerCtrl) & 0x02)
+            {
+                GUSregb(TimerStatus2x8) |= 0x01;
+                GUSregb(IRQStatReg2x6) = 0x10;
+                GUS_irqrequest(state, state->gusirq, 1);
+            }
+        }
+        break;
+    case 0x20A:
+        GUSregb(AdLibStatus2x8) = (GUSbyte) data;
+        break;                 /* AdLibStatus2x8 */
+    case 0x20B:                /* GUS hidden registers */
+        switch (GUSregb(RegCtrl_2xF) & 0x7)
+        {
+        case 0:
+            if (GUSregb(MixerCtrlReg2x0) & 0x40)
+                GUSregb(IRQ_2xB) = (GUSbyte) data; /* control register select bit */
+            else
+                GUSregb(DMA_2xB) = (GUSbyte) data;
+            break;
+            /* case 1-4: general purpose emulation regs */
+        case 5:                                    /* clear stat reg 2xF */
+            GUSregb(StatRead_2xF) = 0; /* ToDo: is this identical with GUS classic? */
+            if (!GUSregb(IRQStatReg2x6))
+                GUS_irqclear(state, state->gusirq);
+            break;
+        case 6:                                    /* Jumper reg (Joystick/MIDI enable) */
+            GUSregb(Jumper_2xB) = (GUSbyte) data;
+            break;
+        default:;
+        }
+        break;
+    case 0x20C:                /* SB2xCd */
+        if (GUSregb(GUS45TimerCtrl) & 0x20)
+        {
+            GUSregb(TimerStatus2x8) |= 0x10; /* SB IRQ enabled? -> set 2xCIRQ bit */
+            GUSregb(IRQStatReg2x6) = 0x10;
+            GUS_irqrequest(state, state->gusirq, 1);
+        }
+    case 0x20D:                /* SB2xCd no IRQ */
+        GUSregb(SB2xCd) = (GUSbyte) data;
+        break;
+    case 0x20E:                /* SB2xE */
+        GUSregb(SB2xE) = (GUSbyte) data;
+        break;
+    case 0x20F:
+        GUSregb(RegCtrl_2xF) = (GUSbyte) data;
+        break;                 /* CtrlReg2xF */
+    case 0x302:                /* VoiceSelReg */
+        GUSregb(VoiceSelReg3x2) = (GUSbyte) data;
+        break;
+    case 0x303:                /* FunkSelReg */
+        GUSregb(FunkSelReg3x3) = (GUSbyte) data;
+        if ((GUSbyte) data == 0x8f) /* set irqstatreg, get voicereg and clear IRQ */
+        {
+            int             voice;
+            if (GUSregd(voicewavetableirq)) /* WavetableIRQ */
+            {
+                for (voice = 0; voice < 31; voice++)
+                {
+                    if (GUSregd(voicewavetableirq) & (1 << voice))
+                    {
+                        GUSregd(voicewavetableirq) ^= (1 << voice); /* clear IRQ bit */
+                        GUSregb(voice << 5) &= 0x7f; /* clear voice reg irq bit */
+                        if (!GUSregd(voicewavetableirq))
+                            GUSregb(IRQStatReg2x6) &= 0xdf;
+                        if (!GUSregb(IRQStatReg2x6))
+                            GUS_irqclear(state, state->gusirq);
+                        GUSregb(SynVoiceIRQ8f) = voice | 0x60; /* (bit==0 => IRQ wartend) */
+                        return;
+                    }
+                }
+            }
+            else if (GUSregd(voicevolrampirq)) /* VolRamp IRQ */
+            {
+                for (voice = 0; voice < 31; voice++)
+                {
+                    if (GUSregd(voicevolrampirq) & (1 << voice))
+                    {
+                        GUSregd(voicevolrampirq) ^= (1 << voice); /* clear IRQ bit */
+                        GUSregb((voice << 5) + VSRVolRampControl) &= 0x7f; /* clear voice volume reg irq bit */
+                        if (!GUSregd(voicevolrampirq))
+                            GUSregb(IRQStatReg2x6) &= 0xbf;
+                        if (!GUSregb(IRQStatReg2x6))
+                            GUS_irqclear(state, state->gusirq);
+                        GUSregb(SynVoiceIRQ8f) = voice | 0x80; /* (bit==0 => IRQ wartend) */
+                        return;
+                    }
+                }
+            }
+            GUSregb(SynVoiceIRQ8f) = 0xe8; /* kein IRQ wartet */
+        }
+        break;
+    case 0x304:
+    case 0x305:
+        {
+            GUSword         writedata = (GUSword) data;
+            GUSword         readmask = 0x0000;
+            if (size == 1)
+            {
+                readmask = 0xff00;
+                writedata &= 0xff;
+                if ((port & 0xff0f) == 0x305)
+                {
+                    writedata = (GUSword) (writedata << 8);
+                    readmask = 0x00ff;
+                }
+            }
+            switch (GUSregb(FunkSelReg3x3))
+            {
+                /* voice specific functions */
+            case 0x00:
+            case 0x01:
+            case 0x02:
+            case 0x03:
+            case 0x04:
+            case 0x05:
+            case 0x06:
+            case 0x07:
+            case 0x08:
+            case 0x09:
+            case 0x0a:
+            case 0x0b:
+            case 0x0c:
+            case 0x0d:
+                {
+                    int             offset;
+                    if (!(GUSregb(GUS4cReset) & 0x01))
+                        break;  /* reset flag active? */
+                    offset = 2 * (GUSregb(FunkSelReg3x3) & 0x0f);
+                    offset += (GUSregb(VoiceSelReg3x2) & 0x1f) << 5; /*  = Voice*32 + Funktion*2 */
+                    GUSregw(offset) = (GUSword) ((GUSregw(offset) & readmask) | writedata);
+                }
+                break;
+                /* voice unspecific functions */
+            case 0x0e:         /* NumVoices */
+                GUSregb(NumVoices) = (GUSbyte) data;
+                break;
+            /* case 0x0f:      */ /* read only */
+                /* common functions */
+            case 0x41:         /* DramDMAContrReg */
+                GUSregb(GUS41DMACtrl) = (GUSbyte) data;
+                if (data & 0x01)
+                    GUS_dmarequest(state);
+                break;
+            case 0x42:         /* DramDMAmemPosReg */
+                GUSregw(GUS42DMAStart) = (GUSregw(GUS42DMAStart) & readmask) | writedata;
+                GUSregb(GUS50DMAHigh) &= 0xf; /* compatibility stuff... */
+                break;
+            case 0x43:         /* DRAMaddrLo */
+                GUSregd(GUSDRAMPOS24bit) =
+                    (GUSregd(GUSDRAMPOS24bit) & (readmask | 0xff0000)) | writedata;
+                break;
+            case 0x44:         /* DRAMaddrHi */
+                GUSregd(GUSDRAMPOS24bit) =
+                    (GUSregd(GUSDRAMPOS24bit) & 0xffff) | ((data & 0x0f) << 16);
+                break;
+            case 0x45:         /* TCtrlReg */
+                GUSregb(GUS45TimerCtrl) = (GUSbyte) data;
+                if (!(data & 0x20))
+                    GUSregb(TimerStatus2x8) &= 0xe7;    /* sb IRQ dis? -> clear 2x8/2xC sb IRQ flags */
+                if (!(data & 0x02))
+                    GUSregb(TimerStatus2x8) &= 0xfe;    /* adlib data IRQ dis? -> clear 2x8 adlib IRQ flag */
+                if (!(GUSregb(TimerStatus2x8) & 0x19))
+                    GUSregb(IRQStatReg2x6) &= 0xef;     /* 0xe6; $$clear IRQ if both IRQ bits are inactive or cleared */
+                /* catch up delayed timer IRQs: */
+                if ((GUSregw(TimerIRQs) > 1) && (GUSregb(TimerDataReg2x9) & 3))
+                {
+                    if (GUSregb(TimerDataReg2x9) & 1)   /* start timer 1 (80us decrement rate) */
+                    {
+                        if (!(GUSregb(TimerDataReg2x9) & 0x40))
+                            GUSregb(TimerStatus2x8) |= 0xc0;    /* maskable bits */
+                        if (data & 4) /* timer1 irq enable */
+                        {
+                            GUSregb(TimerStatus2x8) |= 4;       /* nonmaskable bit */
+                            GUSregb(IRQStatReg2x6) |= 4;        /* timer 1 irq pending */
+                        }
+                    }
+                    if (GUSregb(TimerDataReg2x9) & 2)   /* start timer 2 (320us decrement rate) */
+                    {
+                        if (!(GUSregb(TimerDataReg2x9) & 0x20))
+                            GUSregb(TimerStatus2x8) |= 0xa0;    /* maskable bits */
+                        if (data & 8) /* timer2 irq enable */
+                        {
+                            GUSregb(TimerStatus2x8) |= 2;       /* nonmaskable bit */
+                            GUSregb(IRQStatReg2x6) |= 8;        /* timer 2 irq pending */
+                        }
+                    }
+                    GUSregw(TimerIRQs)--;
+                    if (GUSregw(BusyTimerIRQs) > 1)
+                        GUSregw(BusyTimerIRQs)--;
+                    else
+                        GUSregw(BusyTimerIRQs) =
+                            GUS_irqrequest(state, state->gusirq, GUSregw(TimerIRQs));
+                }
+                else
+                    GUSregw(TimerIRQs) = 0;
+
+                if (!(data & 0x04))
+                {
+                    GUSregb(TimerStatus2x8) &= 0xfb; /* clear non-maskable timer1 bit */
+                    GUSregb(IRQStatReg2x6)  &= 0xfb;
+                }
+                if (!(data & 0x08))
+                {
+                    GUSregb(TimerStatus2x8) &= 0xfd; /* clear non-maskable timer2 bit */
+                    GUSregb(IRQStatReg2x6)  &= 0xf7;
+                }
+                if (!GUSregb(IRQStatReg2x6))
+                    GUS_irqclear(state, state->gusirq);
+                break;
+            case 0x46:          /* Counter1 */
+                GUSregb(GUS46Counter1) = (GUSbyte) data;
+                break;
+            case 0x47:          /* Counter2 */
+                GUSregb(GUS47Counter2) = (GUSbyte) data;
+                break;
+            /* case 0x48:       */ /* sampling freq reg not emulated (same as interwave) */
+            case 0x49:          /* SampCtrlReg */
+                GUSregb(GUS49SampCtrl) = (GUSbyte) data;
+                break;
+            /* case 0x4b:       */ /* joystick trim not emulated */
+            case 0x4c:          /* GUSreset */
+                GUSregb(GUS4cReset) = (GUSbyte) data;
+                if (!(GUSregb(GUS4cReset) & 1)) /* reset... */
+                {
+                    GUSregd(voicewavetableirq) = 0;
+                    GUSregd(voicevolrampirq) = 0;
+                    GUSregw(TimerIRQs) = 0;
+                    GUSregw(BusyTimerIRQs) = 0;
+                    GUSregb(NumVoices) = 0xcd;
+                    GUSregb(IRQStatReg2x6) = 0;
+                    GUSregb(TimerStatus2x8) = 0;
+                    GUSregb(AdLibData2x9) = 0;
+                    GUSregb(TimerDataReg2x9) = 0;
+                    GUSregb(GUS41DMACtrl) = 0;
+                    GUSregb(GUS45TimerCtrl) = 0;
+                    GUSregb(GUS49SampCtrl) = 0;
+                    GUSregb(GUS4cReset) &= 0xf9; /* clear IRQ and DAC enable bits */
+                    GUS_irqclear(state, state->gusirq);
+                }
+                /* IRQ enable bit checked elsewhere */
+                /* EnableDAC bit may be used by external callers */
+                break;
+            }
+        }
+        break;
+    case 0x307:                /* DRAMaccess */
+        {
+            GUSbyte        *adr;
+            adr = state->himemaddr + (GUSregd(GUSDRAMPOS24bit) & 0xfffff);
+            *adr = (GUSbyte) data;
+        }
+        break;
+    }
+}
+
+/* Attention when breaking up a single DMA transfer to multiple ones:
+ * it may lead to multiple terminal count interrupts and broken transfers:
+ *
+ * 1. Whenever you transfer a piece of data, the gusemu callback is invoked
+ * 2. The callback may generate a TC irq (if the register was set up to do so)
+ * 3. The irq may result in the program using the GUS to reprogram the GUS
+ *
+ * Some programs also decide to upload by just checking if TC occurs
+ * (via interrupt or a cleared GUS dma flag)
+ * and then start the next transfer, without checking DMA state
+ *
+ * Thus: Always make sure to set the TC flag correctly!
+ *
+ * Note that the genuine GUS had a granularity of 16 bytes/words for low/high DMA
+ * while later cards had atomic granularity provided by an additional GUS50DMAHigh register
+ * GUSemu also uses this register to support byte-granular transfers for better compatibility
+ * with emulators other than GUSemu32
+ */
+
+void gus_dma_transferdata(GUSEmuState * state, char *dma_addr, unsigned int count, int TC)
+{
+    /* this function gets called by the callback function as soon as a DMA transfer is about to start
+     * dma_addr is a translated address within accessible memory, not the physical one,
+     * count is (real dma count register)+1
+     * note that the amount of bytes transfered is fully determined by values in the DMA registers
+     * do not forget to update DMA states after transferring the entire block:
+     * DREQ cleared & TC asserted after the _whole_ transfer */
+
+    char           *srcaddr;
+    char           *destaddr;
+    char            msbmask = 0;
+    GUSbyte        *gusptr;
+    gusptr = state->gusdatapos;
+
+    srcaddr = dma_addr; /* system memory address */
+    {
+        int             offset = (GUSregw(GUS42DMAStart) << 4) + (GUSregb(GUS50DMAHigh) & 0xf);
+        if (state->gusdma >= 4)
+            offset = (offset & 0xc0000) + (2 * (offset & 0x1fff0)); /* 16 bit address translation */
+        destaddr = (char *) state->himemaddr + offset; /* wavetable RAM adress */
+    }
+
+    GUSregw(GUS42DMAStart) += (GUSword)  (count >> 4);                           /* ToDo: add 16bit GUS page limit? */
+    GUSregb(GUS50DMAHigh)   = (GUSbyte) ((count + GUSregb(GUS50DMAHigh)) & 0xf); /* ToDo: add 16bit GUS page limit? */
+
+    if (GUSregb(GUS41DMACtrl) & 0x02)   /* direction, 0 := sysram->gusram */
+    {
+        char           *tmpaddr = destaddr;
+        destaddr = srcaddr;
+        srcaddr = tmpaddr;
+    }
+
+    if ((GUSregb(GUS41DMACtrl) & 0x80) && (!(GUSregb(GUS41DMACtrl) & 0x02)))
+        msbmask = (const char) 0x80;    /* invert MSB */
+    for (; count > 0; count--)
+    {
+        if (GUSregb(GUS41DMACtrl) & 0x40)
+            *(destaddr++) = *(srcaddr++);               /* 16 bit lobyte */
+        else
+            *(destaddr++) = (msbmask ^ (*(srcaddr++))); /* 8 bit */
+        if (state->gusdma >= 4)
+            *(destaddr++) = (msbmask ^ (*(srcaddr++))); /* 16 bit hibyte */
+    }
+
+    if (TC)
+    {
+        (GUSregb(GUS41DMACtrl)) &= 0xfe;        /* clear DMA request bit */
+        if (GUSregb(GUS41DMACtrl) & 0x20)       /* DMA terminal count IRQ */
+        {
+            GUSregb(IRQStatReg2x6) |= 0x80;
+            GUS_irqrequest(state, state->gusirq, 1);
+        }
+    }
+}

Added: trunk/src/host/qemu-neo1973/hw/gusemu_mixer.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/gusemu_mixer.c	2008-01-14 20:40:58 UTC (rev 3831)
+++ trunk/src/host/qemu-neo1973/hw/gusemu_mixer.c	2008-01-14 23:24:21 UTC (rev 3832)
@@ -0,0 +1,240 @@
+/*
+ * GUSEMU32 - mixing engine (similar to Interwave GF1 compatibility)
+ *
+ * Copyright (C) 2000-2007 Tibor "TS" Schütz
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "gusemu.h"
+#include "gustate.h"
+
+#define GUSregb(position)  (*            (gusptr+(position)))
+#define GUSregw(position)  (*(GUSword *) (gusptr+(position)))
+#define GUSregd(position)  (*(GUSdword *)(gusptr+(position)))
+
+#define GUSvoice(position) (*(GUSword *)(voiceptr+(position)))
+
+/* samples are always 16bit stereo (4 bytes each, first right then left interleaved) */
+void gus_mixvoices(GUSEmuState * state, unsigned int playback_freq, unsigned int numsamples,
+                   short *bufferpos)
+{
+    /* note that byte registers are stored in the upper half of each voice register! */
+    GUSbyte        *gusptr;
+    int             Voice;
+    GUSword        *voiceptr;
+
+    unsigned int    count;
+    for (count = 0; count < numsamples * 2; count++)
+        *(bufferpos + count) = 0;       /* clear */
+
+    gusptr = state->gusdatapos;
+    voiceptr = (GUSword *) gusptr;
+    if (!(GUSregb(GUS4cReset) & 0x01))  /* reset flag active? */
+        return;
+
+    for (Voice = 0; Voice <= (GUSregb(NumVoices) & 31); Voice++)
+    {
+        if (GUSvoice(wVSRControl)        &  0x200)
+            GUSvoice(wVSRControl)        |= 0x100; /* voice stop request */
+        if (GUSvoice(wVSRVolRampControl) &  0x200)
+            GUSvoice(wVSRVolRampControl) |= 0x100; /* Volume ramp stop request */
+        if (!(GUSvoice(wVSRControl) & GUSvoice(wVSRVolRampControl) & 0x100)) /* neither voice nor volume calculation active - save some time here ;) */
+        {
+            unsigned int    sample;
+
+            unsigned int    LoopStart = (GUSvoice(wVSRLoopStartHi) << 16) | GUSvoice(wVSRLoopStartLo); /* 23.9 format */
+            unsigned int    LoopEnd   = (GUSvoice(wVSRLoopEndHi)   << 16) | GUSvoice(wVSRLoopEndLo);   /* 23.9 format */
+            unsigned int    CurrPos   = (GUSvoice(wVSRCurrPosHi)   << 16) | GUSvoice(wVSRCurrPosLo);   /* 23.9 format */
+            int             VoiceIncrement = ((((unsigned long) GUSvoice(wVSRFreq) * 44100) / playback_freq) * (14 >> 1)) /
+                                             ((GUSregb(NumVoices) & 31) + 1); /* 6.10 increment/frame to 23.9 increment/sample */
+
+            int             PanningPos = (GUSvoice(wVSRPanning) >> 8) & 0xf;
+
+            unsigned int    Volume32   = 32 * GUSvoice(wVSRCurrVol); /* 32 times larger than original gus for maintaining precision while ramping */
+            unsigned int    StartVol32 = (GUSvoice(wVSRVolRampStartVol) & 0xff00) * 32;
+            unsigned int    EndVol32   = (GUSvoice(wVSRVolRampEndVol)   & 0xff00) * 32;
+            int             VolumeIncrement32 = (32 * 16 * (GUSvoice(wVSRVolRampRate) & 0x3f00) >> 8) >> ((((GUSvoice(wVSRVolRampRate) & 0xc000) >> 8) >> 6) * 3); /* including 1/8/64/512 volume speed divisor */
+            VolumeIncrement32 = (((VolumeIncrement32 * 44100 / 2) / playback_freq) * 14) / ((GUSregb(NumVoices) & 31) + 1); /* adjust ramping speed to playback speed */
+
+            if (GUSvoice(wVSRControl) & 0x4000)
+                VoiceIncrement    = -VoiceIncrement;    /* reverse playback */
+            if (GUSvoice(wVSRVolRampControl) & 0x4000)
+                VolumeIncrement32 = -VolumeIncrement32; /* reverse ramping */
+
+            for (sample = 0; sample < numsamples; sample++)
+            {
+                int             sample1, sample2, Volume;
+                if (GUSvoice(wVSRControl) & 0x400)      /* 16bit */
+                {
+                    int offset = ((CurrPos >> 9) & 0xc0000) + (((CurrPos >> 9) & 0x1ffff) << 1);
+                    GUSchar *adr;
+                    adr = (GUSchar *) state->himemaddr + offset;
+                    sample1 = (*adr & 0xff) + (*(adr + 1) * 256);
+                    sample2 = (*(adr + 2) & 0xff) + (*(adr + 2 + 1) * 256);
+                }
+                else            /* 8bit */
+                {
+                    int offset = (CurrPos >> 9) & 0xfffff;
+                    GUSchar *adr;
+                    adr = (GUSchar *) state->himemaddr + offset;
+                    sample1 = (*adr) * 256;
+                    sample2 = (*(adr + 1)) * 256;
+                }
+
+                Volume = ((((Volume32 >> (4 + 5)) & 0xff) + 256) << (Volume32 >> ((4 + 8) + 5))) / 512; /* semi-logarithmic volume, +5 due to additional precision */
+                sample1 = (((sample1 * Volume) >> 16) * (512 - (CurrPos % 512))) / 512;
+                sample2 = (((sample2 * Volume) >> 16) * (CurrPos % 512)) / 512;
+                sample1 += sample2;
+
+                if (!(GUSvoice(wVSRVolRampControl) & 0x100))
+                {
+                    Volume32 += VolumeIncrement32;
+                    if ((GUSvoice(wVSRVolRampControl) & 0x4000) ? (Volume32 <= StartVol32) : (Volume32 >= EndVol32)) /* ramp up boundary cross */
+                    {
+                        if (GUSvoice(wVSRVolRampControl) & 0x2000)
+                            GUSvoice(wVSRVolRampControl) |= 0x8000;     /* volramp IRQ enabled? -> IRQ wait flag */
+                        if (GUSvoice(wVSRVolRampControl) & 0x800)       /* loop enabled */
+                        {
+                            if (GUSvoice(wVSRVolRampControl) & 0x1000)  /* bidir. loop */
+                            {
+                                GUSvoice(wVSRVolRampControl) ^= 0x4000; /* toggle dir */
+                                VolumeIncrement32 = -VolumeIncrement32;
+                            }
+                            else
+                                Volume32 = (GUSvoice(wVSRVolRampControl) & 0x4000) ? EndVol32 : StartVol32; /* unidir. loop ramp */
+                        }
+                        else
+                        {
+                            GUSvoice(wVSRVolRampControl) |= 0x100;
+                            Volume32 =
+                                (GUSvoice(wVSRVolRampControl) & 0x4000) ? StartVol32 : EndVol32;
+                        }
+                    }
+                }
+                if ((GUSvoice(wVSRVolRampControl) & 0xa000) == 0xa000)  /* volramp IRQ set and enabled? */
+                {
+                    GUSregd(voicevolrampirq) |= 1 << Voice;             /* set irq slot */
+                }
+                else
+                {
+                    GUSregd(voicevolrampirq) &= (~(1 << Voice));        /* clear irq slot */
+                    GUSvoice(wVSRVolRampControl) &= 0x7f00;
+                }
+
+                if (!(GUSvoice(wVSRControl) & 0x100))
+                {
+                    CurrPos += VoiceIncrement;
+                    if ((GUSvoice(wVSRControl) & 0x4000) ? (CurrPos <= LoopStart) : (CurrPos >= LoopEnd)) /* playback boundary cross */
+                    {
+                        if (GUSvoice(wVSRControl) & 0x2000)
+                            GUSvoice(wVSRControl) |= 0x8000;       /* voice IRQ enabled -> IRQ wait flag */
+                        if (GUSvoice(wVSRControl) & 0x800)         /* loop enabled */
+                        {
+                            if (GUSvoice(wVSRControl) & 0x1000)    /* pingpong loop */
+                            {
+                                GUSvoice(wVSRControl) ^= 0x4000;   /* toggle dir */
+                                VoiceIncrement = -VoiceIncrement;
+                            }
+                            else
+                                CurrPos = (GUSvoice(wVSRControl) & 0x4000) ? LoopEnd : LoopStart; /* unidir. loop */
+                        }
+                        else if (!(GUSvoice(wVSRVolRampControl) & 0x400))
+                            GUSvoice(wVSRControl) |= 0x100;        /* loop disabled, rollover check */
+                    }
+                }
+                if ((GUSvoice(wVSRControl) & 0xa000) == 0xa000)    /* wavetable IRQ set and enabled? */
+                {
+                    GUSregd(voicewavetableirq) |= 1 << Voice;      /* set irq slot */
+                }
+                else
+                {
+                    GUSregd(voicewavetableirq) &= (~(1 << Voice)); /* clear irq slot */
+                    GUSvoice(wVSRControl) &= 0x7f00;
+                }
+
+                /* mix samples into buffer */
+                *(bufferpos + 2 * sample)     += (short) ((sample1 * PanningPos) >> 4);        /* right */
+                *(bufferpos + 2 * sample + 1) += (short) ((sample1 * (15 - PanningPos)) >> 4); /* left */
+            }
+            /* write back voice and volume */
+            GUSvoice(wVSRCurrVol)   = Volume32 / 32;
+            GUSvoice(wVSRCurrPosHi) = CurrPos >> 16;
+            GUSvoice(wVSRCurrPosLo) = CurrPos & 0xffff;
+        }
+        voiceptr += 16; /* next voice */
+    }
+}
+
+void gus_irqgen(GUSEmuState * state, unsigned int elapsed_time)
+/* time given in microseconds */
+{
+    int             requestedIRQs = 0;
+    GUSbyte        *gusptr;
+    gusptr = state->gusdatapos;
+    if (GUSregb(TimerDataReg2x9) & 1) /* start timer 1 (80us decrement rate) */
+    {
+        unsigned int    timer1fraction = state->timer1fraction;
+        int             newtimerirqs;
+        newtimerirqs          = (elapsed_time + timer1fraction) / (80 * (256 - GUSregb(GUS46Counter1)));
+        state->timer1fraction = (elapsed_time + timer1fraction) % (80 * (256 - GUSregb(GUS46Counter1)));
+        if (newtimerirqs)
+        {
+            if (!(GUSregb(TimerDataReg2x9) & 0x40))
+                GUSregb(TimerStatus2x8) |= 0xc0; /* maskable bits */
+            if (GUSregb(GUS45TimerCtrl) & 4)     /* timer1 irq enable */
+            {
+                GUSregb(TimerStatus2x8) |= 4;    /* nonmaskable bit */
+                GUSregb(IRQStatReg2x6)  |= 4;    /* timer 1 irq pending */
+                GUSregw(TimerIRQs) += newtimerirqs;
+                requestedIRQs += newtimerirqs;
+            }
+        }
+    }
+    if (GUSregb(TimerDataReg2x9) & 2) /* start timer 2 (320us decrement rate) */
+    {
+        unsigned int timer2fraction = state->timer2fraction;
+        int             newtimerirqs;
+        newtimerirqs          = (elapsed_time + timer2fraction) / (320 * (256 - GUSregb(GUS47Counter2)));
+        state->timer2fraction = (elapsed_time + timer2fraction) % (320 * (256 - GUSregb(GUS47Counter2)));
+        if (newtimerirqs)
+        {
+            if (!(GUSregb(TimerDataReg2x9) & 0x20))
+                GUSregb(TimerStatus2x8) |= 0xa0; /* maskable bits */
+            if (GUSregb(GUS45TimerCtrl) & 8)     /* timer2 irq enable */
+            {
+                GUSregb(TimerStatus2x8) |= 2;    /* nonmaskable bit */
+                GUSregb(IRQStatReg2x6)  |= 8;    /* timer 2 irq pending */
+                GUSregw(TimerIRQs) += newtimerirqs;
+                requestedIRQs += newtimerirqs;
+            }
+        }
+    }
+    if (GUSregb(GUS4cReset) & 0x4) /* synth IRQ enable */
+    {
+        if (GUSregd(voicewavetableirq))
+            GUSregb(IRQStatReg2x6) |= 0x20;
+        if (GUSregd(voicevolrampirq))
+            GUSregb(IRQStatReg2x6) |= 0x40;
+    }
+    if ((!requestedIRQs) && GUSregb(IRQStatReg2x6))
+        requestedIRQs++;
+    if (GUSregb(IRQStatReg2x6))
+        GUSregw(BusyTimerIRQs) = GUS_irqrequest(state, state->gusirq, requestedIRQs);
+}

Added: trunk/src/host/qemu-neo1973/hw/gustate.h
===================================================================
--- trunk/src/host/qemu-neo1973/hw/gustate.h	2008-01-14 20:40:58 UTC (rev 3831)
+++ trunk/src/host/qemu-neo1973/hw/gustate.h	2008-01-14 23:24:21 UTC (rev 3832)
@@ -0,0 +1,132 @@
+/*
+ * GUSEMU32 - persistent GUS register state
+ *
+ * Copyright (C) 2000-2007 Tibor "TS" Schütz
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef GUSTATE_H
+#define GUSTATE_H
+
+/*state block offset*/
+#define gusdata (0)
+
+/* data stored using this structure is in host byte order! */
+
+/*access type*/
+#define PortRead  (0)
+#define PortWrite (1)
+
+#define Port8Bitacc  (0)
+#define Port16Bitacc (1)
+
+/*voice register offsets (in bytes)*/
+#define VSRegs (0)
+#define VSRControl          (0)
+#define VSRegsEnd (VSRControl+VSRegs + 32*(16*2))
+#define VSRFreq             (2)
+#define VSRLoopStartHi      (4)
+#define VSRLoopStartLo      (6)
+#define VSRLoopEndHi        (8)
+#define VSRLoopEndLo       (10)
+#define VSRVolRampRate     (12)
+#define VSRVolRampStartVol (14)
+#define VSRVolRampEndVol   (16)
+#define VSRCurrVol         (18)
+#define VSRCurrPosHi       (20)
+#define VSRCurrPosLo       (22)
+#define VSRPanning         (24)
+#define VSRVolRampControl  (26)
+
+/*voice register offsets (in words)*/
+#define wVSRegs (0)
+#define wVSRControl         (0)
+#define wVSRegsEnd (wVSRControl+wVSRegs + 32*(16))
+#define wVSRFreq            (1)
+#define wVSRLoopStartHi     (2)
+#define wVSRLoopStartLo     (3)
+#define wVSRLoopEndHi       (4)
+#define wVSRLoopEndLo       (5)
+#define wVSRVolRampRate     (6)
+#define wVSRVolRampStartVol (7)
+#define wVSRVolRampEndVol   (8)
+#define wVSRCurrVol         (9)
+#define wVSRCurrPosHi      (10)
+#define wVSRCurrPosLo      (11)
+#define wVSRPanning        (12)
+#define wVSRVolRampControl (13)
+
+/*GUS register state block: 32 voices, padding filled with remaining registers*/
+#define DataRegLoByte3x4  (VSRVolRampControl+2)
+#define  DataRegWord3x4 (DataRegLoByte3x4)
+#define DataRegHiByte3x5  (VSRVolRampControl+2       +1)
+#define DMA_2xB (VSRVolRampControl+2+2)
+#define IRQ_2xB (VSRVolRampControl+2+3)
+
+#define RegCtrl_2xF       (VSRVolRampControl+2+(16*2))
+#define Jumper_2xB        (VSRVolRampControl+2+(16*2)+1)
+#define GUS42DMAStart     (VSRVolRampControl+2+(16*2)+2)
+
+#define GUS43DRAMIOlo     (VSRVolRampControl+2+(16*2)*2)
+#define  GUSDRAMPOS24bit (GUS43DRAMIOlo)
+#define GUS44DRAMIOhi     (VSRVolRampControl+2+(16*2)*2+2)
+
+#define voicewavetableirq (VSRVolRampControl+2+(16*2)*3) /* voice IRQ pseudoqueue: 1 bit per voice */
+
+#define voicevolrampirq   (VSRVolRampControl+2+(16*2)*4) /* voice IRQ pseudoqueue: 1 bit per voice */
+
+#define startvoices       (VSRVolRampControl+2+(16*2)*5) /* statistics / optimizations */
+
+#define IRQStatReg2x6     (VSRVolRampControl+2+(16*2)*6)
+#define TimerStatus2x8    (VSRVolRampControl+2+(16*2)*6+1)
+#define TimerDataReg2x9   (VSRVolRampControl+2+(16*2)*6+2)
+#define MixerCtrlReg2x0   (VSRVolRampControl+2+(16*2)*6+3)
+
+#define VoiceSelReg3x2    (VSRVolRampControl+2+(16*2)*7)
+#define FunkSelReg3x3     (VSRVolRampControl+2+(16*2)*7+1)
+#define AdLibStatus2x8    (VSRVolRampControl+2+(16*2)*7+2)
+#define StatRead_2xF      (VSRVolRampControl+2+(16*2)*7+3)
+
+#define GUS48SampSpeed    (VSRVolRampControl+2+(16*2)*8)
+#define GUS41DMACtrl      (VSRVolRampControl+2+(16*2)*8+1)
+#define GUS45TimerCtrl    (VSRVolRampControl+2+(16*2)*8+2)
+#define GUS46Counter1     (VSRVolRampControl+2+(16*2)*8+3)
+
+#define GUS47Counter2     (VSRVolRampControl+2+(16*2)*9)
+#define GUS49SampCtrl     (VSRVolRampControl+2+(16*2)*9+1)
+#define GUS4cReset        (VSRVolRampControl+2+(16*2)*9+2)
+#define NumVoices         (VSRVolRampControl+2+(16*2)*9+3)
+
+#define TimerIRQs         (VSRVolRampControl+2+(16*2)*10)   /* delayed IRQ, statistics */
+#define BusyTimerIRQs     (VSRVolRampControl+2+(16*2)*10+2) /* delayed IRQ, statistics */
+
+#define AdLibCommand2xA   (VSRVolRampControl+2+(16*2)*11)
+#define AdLibData2x9      (VSRVolRampControl+2+(16*2)*11+1)
+#define SB2xCd            (VSRVolRampControl+2+(16*2)*11+2)
+#define SB2xE             (VSRVolRampControl+2+(16*2)*11+3)
+
+#define SynVoiceIRQ8f     (VSRVolRampControl+2+(16*2)*12)
+#define GUS50DMAHigh      (VSRVolRampControl+2+(16*2)*12+1)
+
+#define portaccesses (VSRegsEnd) /* statistics / suspend mode */
+
+#define gusdataend (VSRegsEnd+4)
+
+#endif  /* gustate.h */

Modified: trunk/src/host/qemu-neo1973/hw/ide.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/ide.c	2008-01-14 20:40:58 UTC (rev 3831)
+++ trunk/src/host/qemu-neo1973/hw/ide.c	2008-01-14 23:24:21 UTC (rev 3832)
@@ -1,5 +1,5 @@
 /*
- * QEMU IDE disk and CD-ROM Emulator
+ * QEMU IDE disk and CD/DVD-ROM Emulator
  *
  * Copyright (c) 2003 Fabrice Bellard
  * Copyright (c) 2006 Openedhand Ltd.
@@ -284,6 +284,58 @@
  * of MODE_SENSE_POWER_PAGE */
 #define GPMODE_CDROM_PAGE		0x0d
 
+/*
+ * Based on values from <linux/cdrom.h> but extending CD_MINS
+ * to the maximum common size allowed by the Orange's Book ATIP
+ *
+ * 90 and 99 min CDs are also available but using them as the
+ * upper limit reduces the effectiveness of the heuristic to
+ * detect DVDs burned to less than 25% of their maximum capacity
+ */
+
+/* Some generally useful CD-ROM information */
+#define CD_MINS                       80 /* max. minutes per CD */
+#define CD_SECS                       60 /* seconds per minute */
+#define CD_FRAMES                     75 /* frames per second */
+#define CD_FRAMESIZE                2048 /* bytes per frame, "cooked" mode */
+#define CD_MAX_BYTES       (CD_MINS * CD_SECS * CD_FRAMES * CD_FRAMESIZE)
+#define CD_MAX_SECTORS     (CD_MAX_BYTES / 512)
+
+/*
+ * The MMC values are not IDE specific and might need to be moved
+ * to a common header if they are also needed for the SCSI emulation
+ */
+
+/* Profile list from MMC-6 revision 1 table 91 */
+#define MMC_PROFILE_NONE                0x0000
+#define MMC_PROFILE_CD_ROM              0x0008
+#define MMC_PROFILE_CD_R                0x0009
+#define MMC_PROFILE_CD_RW               0x000A
+#define MMC_PROFILE_DVD_ROM             0x0010
+#define MMC_PROFILE_DVD_R_SR            0x0011
+#define MMC_PROFILE_DVD_RAM             0x0012
+#define MMC_PROFILE_DVD_RW_RO           0x0013
+#define MMC_PROFILE_DVD_RW_SR           0x0014
+#define MMC_PROFILE_DVD_R_DL_SR         0x0015
+#define MMC_PROFILE_DVD_R_DL_JR         0x0016
+#define MMC_PROFILE_DVD_RW_DL           0x0017
+#define MMC_PROFILE_DVD_DDR             0x0018
+#define MMC_PROFILE_DVD_PLUS_RW         0x001A
+#define MMC_PROFILE_DVD_PLUS_R          0x001B
+#define MMC_PROFILE_DVD_PLUS_RW_DL      0x002A
+#define MMC_PROFILE_DVD_PLUS_R_DL       0x002B
+#define MMC_PROFILE_BD_ROM              0x0040
+#define MMC_PROFILE_BD_R_SRM            0x0041
+#define MMC_PROFILE_BD_R_RRM            0x0042
+#define MMC_PROFILE_BD_RE               0x0043
+#define MMC_PROFILE_HDDVD_ROM           0x0050
+#define MMC_PROFILE_HDDVD_R             0x0051
+#define MMC_PROFILE_HDDVD_RAM           0x0052
+#define MMC_PROFILE_HDDVD_RW            0x0053
+#define MMC_PROFILE_HDDVD_R_DL          0x0058
+#define MMC_PROFILE_HDDVD_RW_DL         0x005A
+#define MMC_PROFILE_INVALID             0xFFFF
+
 #define ATAPI_INT_REASON_CD             0x01 /* 0 = data transfer */
 #define ATAPI_INT_REASON_IO             0x02 /* 1 = transfer to the host */
 #define ATAPI_INT_REASON_REL            0x04
@@ -540,7 +592,7 @@
     put_le16(p + 21, 512); /* cache size in sectors */
     put_le16(p + 22, 4); /* ecc bytes */
     padstr((char *)(p + 23), QEMU_VERSION, 8); /* firmware version */
-    padstr((char *)(p + 27), "QEMU CD-ROM", 40); /* model */
+    padstr((char *)(p + 27), "QEMU DVD-ROM", 40); /* model */
     put_le16(p + 48, 1); /* dword I/O (XXX: should not be set on CDROM) */
 #ifdef USE_DMA_CDROM
     put_le16(p + 49, 1 << 9 | 1 << 8); /* DMA and LBA supported */
@@ -1290,6 +1342,22 @@
     }
 }
 
+static inline uint8_t ide_atapi_set_profile(uint8_t *buf, uint8_t *index,
+                                            uint16_t profile)
+{
+    uint8_t *buf_profile = buf + 12; /* start of profiles */
+
+    buf_profile += ((*index) * 4); /* start of indexed profile */
+    cpu_to_ube16 (buf_profile, profile);
+    buf_profile[2] = ((buf_profile[0] == buf[6]) && (buf_profile[1] == buf[7]));
+
+    /* each profile adds 4 bytes to the response */
+    (*index)++;
+    buf[11] += 4; /* Additional Length */
+
+    return 4;
+}
+
 static void ide_atapi_cmd(IDEState *s)
 {
     const uint8_t *packet;
@@ -1634,13 +1702,13 @@
         buf[6] = 0; /* reserved */
         buf[7] = 0; /* reserved */
         padstr8(buf + 8, 8, "QEMU");
-        padstr8(buf + 16, 16, "QEMU CD-ROM");
+        padstr8(buf + 16, 16, "QEMU DVD-ROM");
         padstr8(buf + 32, 4, QEMU_VERSION);
         ide_atapi_cmd_reply(s, 36, max_len);
         break;
     case GPCMD_GET_CONFIGURATION:
         {
-            uint64_t total_sectors;
+            uint32_t len;
 
             /* only feature 0 is supported */
             if (packet[2] != 0 || packet[3] != 0) {
@@ -1648,17 +1716,46 @@
                                     ASC_INV_FIELD_IN_CMD_PACKET);
                 break;
             }
-            memset(buf, 0, 32);
-            bdrv_get_geometry(s->bs, &total_sectors);
-            buf[3] = 16;
-            buf[7] = total_sectors <= 1433600 ? 0x08 : 0x10; /* current profile */
-            buf[10] = 0x10 | 0x1;
-            buf[11] = 0x08; /* size of profile list */
-            buf[13] = 0x10; /* DVD-ROM profile */
-            buf[14] = buf[7] == 0x10; /* (in)active */
-            buf[17] = 0x08; /* CD-ROM profile */
-            buf[18] = buf[7] == 0x08; /* (in)active */
-            ide_atapi_cmd_reply(s, 32, 32);
+
+            /* XXX: could result in alignment problems in some architectures */
+            max_len = ube16_to_cpu(packet + 7);
+            /*
+             * XXX: avoid overflow for io_buffer if max_len is bigger than the
+             *      size of that buffer (dimensioned to max number of sectors
+             *      to transfer at once)
+             *
+             *      Only a problem if the feature/profiles grow exponentially.
+             */
+            if (max_len > 512) /* XXX: assume 1 sector */
+                max_len = 512;
+
+            memset(buf, 0, max_len);
+            /* 
+             * the number of sectors from the media tells us which profile
+             * to use as current.  0 means there is no media
+             *
+             * XXX: fails to detect correctly DVDs with less data burned
+             *      than what a CD can hold
+             */
+            if ((s -> nb_sectors)) {
+                if ((s -> nb_sectors > CD_MAX_SECTORS))
+                    cpu_to_ube16(buf + 6, MMC_PROFILE_DVD_ROM);
+                else
+                    cpu_to_ube16(buf + 6, MMC_PROFILE_CD_ROM);
+            }
+
+            len = 8; /* header completed */
+            if (max_len > len) {
+                uint8_t index = 0;
+
+                buf[10] = 0x02 | 0x01; /* persistent and current */
+                len += 4; /* header */
+                len += ide_atapi_set_profile(buf, &index, MMC_PROFILE_DVD_ROM);
+                len += ide_atapi_set_profile(buf, &index, MMC_PROFILE_CD_ROM);
+            }
+            cpu_to_ube32(buf, len - 4); /* data length */
+
+            ide_atapi_cmd_reply(s, len, max_len);
             break;
         }
     default:
@@ -2044,7 +2141,7 @@
             break;
         case WIN_DIAGNOSE:
             ide_set_signature(s);
-            s->status = 0x00; /* NOTE: READY is _not_ set */
+            s->status = READY_STAT;
             s->error = 0x01;
             ide_set_irq(s);
             break;

Modified: trunk/src/host/qemu-neo1973/hw/sb16.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/sb16.c	2008-01-14 20:40:58 UTC (rev 3831)
+++ trunk/src/host/qemu-neo1973/hw/sb16.c	2008-01-14 23:24:21 UTC (rev 3832)
@@ -1193,6 +1193,12 @@
     SB16State *s = opaque;
     int till, copy, written, free;
 
+    if (s->block_size <= 0) {
+        dolog ("invalid block size=%d nchan=%d dma_pos=%d dma_len=%d\n",
+               s->block_size, nchan, dma_pos, dma_len);
+        return dma_pos;
+    }
+
     if (s->left_till_irq < 0) {
         s->left_till_irq = s->block_size;
     }

Modified: trunk/src/host/qemu-neo1973/hw/usb-hid.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/usb-hid.c	2008-01-14 20:40:58 UTC (rev 3831)
+++ trunk/src/host/qemu-neo1973/hw/usb-hid.c	2008-01-14 23:24:21 UTC (rev 3832)
@@ -262,7 +262,9 @@
     0x81, 0x02, 0x95, 0x01, 0x75, 0x05, 0x81, 0x01,
     0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x15, 0x81,
     0x25, 0x7F, 0x75, 0x08, 0x95, 0x02, 0x81, 0x06,
-    0xC0, 0xC0,
+    0x05, 0x01, 0x09, 0x38, 0x15, 0x81, 0x25, 0x7F,
+    0x35, 0x00, 0x45, 0x00, 0x75, 0x08, 0x95, 0x01,
+    0x81, 0x02, 0xC0, 0xC0,
 };
 
 static const uint8_t qemu_tablet_hid_report_descriptor[] = {

Added: trunk/src/host/qemu-neo1973/hw/usb-serial.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/usb-serial.c	2008-01-14 20:40:58 UTC (rev 3831)
+++ trunk/src/host/qemu-neo1973/hw/usb-serial.c	2008-01-14 23:24:21 UTC (rev 3832)
@@ -0,0 +1,549 @@
+/*
+ * FTDI FT232BM Device emulation
+ *
+ * Copyright (c) 2006 CodeSourcery.
+ * Copyright (c) 2008 Samuel Thibault <samuel.thibault at ens-lyon.org>
+ * Written by Paul Brook, reused for FTDI by Samuel Thibault
+ *
+ * This code is licenced under the LGPL.
+ */
+
+#include "qemu-common.h"
+#include "usb.h"
+#include "qemu-char.h"
+
+//#define DEBUG_Serial
+
+#ifdef DEBUG_Serial
+#define DPRINTF(fmt, args...) \
+do { printf("usb-serial: " fmt , ##args); } while (0)
+#else
+#define DPRINTF(fmt, args...) do {} while(0)
+#endif
+
+#define RECV_BUF 384
+#define SEND_BUF 128        // Not used for now
+
+/* Commands */
+#define FTDI_RESET		0
+#define FTDI_SET_MDM_CTRL	1
+#define FTDI_SET_FLOW_CTRL	2
+#define FTDI_SET_BAUD		3
+#define FTDI_SET_DATA		4
+#define FTDI_GET_MDM_ST		5
+#define FTDI_SET_EVENT_CHR	6
+#define FTDI_SET_ERROR_CHR	7
+#define FTDI_SET_LATENCY	9
+#define FTDI_GET_LATENCY	10
+
+#define DeviceOutVendor	((USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_DEVICE)<<8)
+#define DeviceInVendor	((USB_DIR_IN |USB_TYPE_VENDOR|USB_RECIP_DEVICE)<<8)
+
+/* RESET */
+
+#define FTDI_RESET_SIO	0
+#define FTDI_RESET_RX	1
+#define FTDI_RESET_TX	2
+
+/* SET_MDM_CTRL */
+
+#define FTDI_MDM_CTRL	3
+#define FTDI_DTR	1
+#define FTDI_RTS	2
+
+/* SET_FLOW_CTRL */
+
+#define FTDI_RTS_CTS_HS		1
+#define FTDI_DTR_DSR_HS		2
+#define FTDI_XON_XOFF_HS	4
+
+/* SET_DATA */
+
+#define FTDI_PARITY	(0x7 << 8)
+#define FTDI_ODD	(0x1 << 8)
+#define FTDI_EVEN	(0x2 << 8)
+#define FTDI_MARK	(0x3 << 8)
+#define FTDI_SPACE	(0x4 << 8)
+
+#define FTDI_STOP	(0x3 << 11)
+#define FTDI_STOP1	(0x0 << 11)
+#define FTDI_STOP15	(0x1 << 11)
+#define FTDI_STOP2	(0x2 << 11)
+
+/* GET_MDM_ST */
+/* TODO: should be sent every 40ms */
+#define FTDI_CTS  (1<<4)        // CTS line status
+#define FTDI_DSR  (1<<5)        // DSR line status
+#define FTDI_RI   (1<<6)        // RI line status
+#define FTDI_RLSD (1<<7)        // Receive Line Signal Detect
+
+/* Status */
+
+#define FTDI_DR   (1<<0)        // Data Ready
+#define FTDI_OE   (1<<1)        // Overrun Err
+#define FTDI_PE   (1<<2)        // Parity Err
+#define FTDI_FE   (1<<3)        // Framing Err
+#define FTDI_BI   (1<<4)        // Break Interrupt
+#define FTDI_THRE (1<<5)        // Transmitter Holding Register
+#define FTDI_TEMT (1<<6)        // Transmitter Empty
+#define FTDI_FIFO (1<<7)        // Error in FIFO
+
+typedef struct {
+    USBDevice dev;
+    uint16_t vendorid;
+    uint16_t productid;
+    uint8_t recv_buf[RECV_BUF];
+    uint8_t recv_ptr;
+    uint8_t recv_used;
+    uint8_t send_buf[SEND_BUF];
+    uint8_t event_chr;
+    uint8_t error_chr;
+    uint8_t event_trigger;
+    uint8_t lines;
+    QEMUSerialSetParams params;
+    int latency;        /* ms */
+    CharDriverState *cs;
+} USBSerialState;
+
+static const uint8_t qemu_serial_dev_descriptor[] = {
+        0x12,       /*  u8 bLength; */
+        0x01,       /*  u8 bDescriptorType; Device */
+        0x00, 0x02, /*  u16 bcdUSB; v2.0 */
+
+        0x00,       /*  u8  bDeviceClass; */
+        0x00,       /*  u8  bDeviceSubClass; */
+        0x00,       /*  u8  bDeviceProtocol; [ low/full speeds only ] */
+        0x08,       /*  u8  bMaxPacketSize0; 8 Bytes */
+
+        /* Vendor and product id are arbitrary.  */
+        0x03, 0x04, /*  u16 idVendor; */
+        0x00, 0xFF, /*  u16 idProduct; */
+        0x00, 0x04, /*  u16 bcdDevice */
+
+        0x01,       /*  u8  iManufacturer; */
+        0x02,       /*  u8  iProduct; */
+        0x03,       /*  u8  iSerialNumber; */
+        0x01        /*  u8  bNumConfigurations; */
+};
+
+static const uint8_t qemu_serial_config_descriptor[] = {
+
+        /* one configuration */
+        0x09,       /*  u8  bLength; */
+        0x02,       /*  u8  bDescriptorType; Configuration */
+        0x20, 0x00, /*  u16 wTotalLength; */
+        0x01,       /*  u8  bNumInterfaces; (1) */
+        0x01,       /*  u8  bConfigurationValue; */
+        0x00,       /*  u8  iConfiguration; */
+        0x80,       /*  u8  bmAttributes;
+                                 Bit 7: must be set,
+                                     6: Self-powered,
+                                     5: Remote wakeup,
+                                     4..0: resvd */
+        100/2,       /*  u8  MaxPower; */
+
+        /* one interface */
+        0x09,       /*  u8  if_bLength; */
+        0x04,       /*  u8  if_bDescriptorType; Interface */
+        0x00,       /*  u8  if_bInterfaceNumber; */
+        0x00,       /*  u8  if_bAlternateSetting; */
+        0x02,       /*  u8  if_bNumEndpoints; */
+        0xff,       /*  u8  if_bInterfaceClass; Vendor Specific */
+        0xff,       /*  u8  if_bInterfaceSubClass; Vendor Specific */
+        0xff,       /*  u8  if_bInterfaceProtocol; Vendor Specific */
+        0x02,       /*  u8  if_iInterface; */
+
+        /* Bulk-In endpoint */
+        0x07,       /*  u8  ep_bLength; */
+        0x05,       /*  u8  ep_bDescriptorType; Endpoint */
+        0x81,       /*  u8  ep_bEndpointAddress; IN Endpoint 1 */
+        0x02,       /*  u8  ep_bmAttributes; Bulk */
+        0x40, 0x00, /*  u16 ep_wMaxPacketSize; */
+        0x00,       /*  u8  ep_bInterval; */
+
+        /* Bulk-Out endpoint */
+        0x07,       /*  u8  ep_bLength; */
+        0x05,       /*  u8  ep_bDescriptorType; Endpoint */
+        0x02,       /*  u8  ep_bEndpointAddress; OUT Endpoint 2 */
+        0x02,       /*  u8  ep_bmAttributes; Bulk */
+        0x40, 0x00, /*  u16 ep_wMaxPacketSize; */
+        0x00        /*  u8  ep_bInterval; */
+};
+
+static void usb_serial_reset(USBSerialState *s)
+{
+    /* TODO: Set flow control to none */
+    s->event_chr = 0x0d;
+    s->event_trigger = 0;
+    s->recv_ptr = 0;
+    s->recv_used = 0;
+    /* TODO: purge in char driver */
+    s->lines &= ~(FTDI_DTR|FTDI_RTS);
+}
+
+static void usb_serial_handle_reset(USBDevice *dev)
+{
+    USBSerialState *s = (USBSerialState *)dev;
+
+    DPRINTF("Reset\n");
+
+    usb_serial_reset(s);
+    /* TODO: Reset char device, send BREAK? */
+}
+
+static int usb_serial_handle_control(USBDevice *dev, int request, int value,
+                                  int index, int length, uint8_t *data)
+{
+    USBSerialState *s = (USBSerialState *)dev;
+    int ret = 0;
+
+    //DPRINTF("got control %x, value %x\n",request, value);
+    switch (request) {
+    case DeviceRequest | USB_REQ_GET_STATUS:
+        data[0] = (0 << USB_DEVICE_SELF_POWERED) |
+            (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP);
+        data[1] = 0x00;
+        ret = 2;
+        break;
+    case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
+        if (value == USB_DEVICE_REMOTE_WAKEUP) {
+            dev->remote_wakeup = 0;
+        } else {
+            goto fail;
+        }
+        ret = 0;
+        break;
+    case DeviceOutRequest | USB_REQ_SET_FEATURE:
+        if (value == USB_DEVICE_REMOTE_WAKEUP) {
+            dev->remote_wakeup = 1;
+        } else {
+            goto fail;
+        }
+        ret = 0;
+        break;
+    case DeviceOutRequest | USB_REQ_SET_ADDRESS:
+        dev->addr = value;
+        ret = 0;
+        break;
+    case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
+        switch(value >> 8) {
+        case USB_DT_DEVICE:
+            memcpy(data, qemu_serial_dev_descriptor,
+                   sizeof(qemu_serial_dev_descriptor));
+            data[8] = s->vendorid & 0xff;
+            data[9] = ((s->vendorid) >> 8) & 0xff;
+            data[10] = s->productid & 0xff;
+            data[11] = ((s->productid) >> 8) & 0xff;
+            ret = sizeof(qemu_serial_dev_descriptor);
+            break;
+        case USB_DT_CONFIG:
+            memcpy(data, qemu_serial_config_descriptor,
+                   sizeof(qemu_serial_config_descriptor));
+            ret = sizeof(qemu_serial_config_descriptor);
+            break;
+        case USB_DT_STRING:
+            switch(value & 0xff) {
+            case 0:
+                /* language ids */
+                data[0] = 4;
+                data[1] = 3;
+                data[2] = 0x09;
+                data[3] = 0x04;
+                ret = 4;
+                break;
+            case 1:
+                /* vendor description */
+                ret = set_usb_string(data, "QEMU " QEMU_VERSION);
+                break;
+            case 2:
+                /* product description */
+                ret = set_usb_string(data, "QEMU USB SERIAL");
+                break;
+            case 3:
+                /* serial number */
+                ret = set_usb_string(data, "1");
+                break;
+            default:
+                goto fail;
+            }
+            break;
+        default:
+            goto fail;
+        }
+        break;
+    case DeviceRequest | USB_REQ_GET_CONFIGURATION:
+        data[0] = 1;
+        ret = 1;
+        break;
+    case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
+        ret = 0;
+        break;
+    case DeviceRequest | USB_REQ_GET_INTERFACE:
+        data[0] = 0;
+        ret = 1;
+        break;
+    case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
+        ret = 0;
+        break;
+    case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
+        ret = 0;
+        break;
+
+        /* Class specific requests.  */
+    case DeviceOutVendor | FTDI_RESET:
+        switch (value) {
+        case FTDI_RESET_SIO:
+            usb_serial_reset(s);
+            break;
+        case FTDI_RESET_RX:
+            s->recv_ptr = 0;
+            s->recv_used = 0;
+            /* TODO: purge from char device */
+            break;
+        case FTDI_RESET_TX:
+            /* TODO: purge from char device */
+            break;
+        }
+        break;
+    case DeviceOutVendor | FTDI_SET_MDM_CTRL:
+        s->lines = value & FTDI_MDM_CTRL;
+        break;
+    case DeviceOutVendor | FTDI_SET_FLOW_CTRL:
+        /* TODO: ioctl */
+        break;
+    case DeviceOutVendor | FTDI_SET_BAUD: {
+        static const int subdivisors8[8] = { 0, 4, 2, 1, 3, 5, 6, 7 };
+        int subdivisor8 = subdivisors8[((value & 0xc000) >> 14)
+                                     | ((index & 1) << 2)];
+        int divisor = value & 0x3fff;
+
+        /* chip special cases */
+        if (divisor == 1 && subdivisor8 == 0)
+            subdivisor8 = 4;
+        if (divisor == 0 && subdivisor8 == 0)
+            divisor = 1;
+
+        s->params.speed = (48000000 / 2) / (8 * divisor + subdivisor8);
+        qemu_chr_ioctl(s->cs, CHR_IOCTL_SERIAL_SET_PARAMS, &s->params);
+        break;
+    }
+    case DeviceOutVendor | FTDI_SET_DATA:
+        switch (value & FTDI_PARITY) {
+            case 0:
+                s->params.parity = 'N';
+                break;
+            case FTDI_ODD:
+                s->params.parity = 'O';
+                break;
+            case FTDI_EVEN:
+                s->params.parity = 'E';
+                break;
+            default:
+                DPRINTF("unsupported parity %d\n", value & FTDI_PARITY);
+                goto fail;
+        }
+        switch (value & FTDI_STOP) {
+            case FTDI_STOP1:
+                s->params.stop_bits = 1;
+                break;
+            case FTDI_STOP2:
+                s->params.stop_bits = 2;
+                break;
+            default:
+                DPRINTF("unsupported stop bits %d\n", value & FTDI_STOP);
+                goto fail;
+        }
+        qemu_chr_ioctl(s->cs, CHR_IOCTL_SERIAL_SET_PARAMS, &s->params);
+        /* TODO: TX ON/OFF */
+        break;
+    case DeviceInVendor | FTDI_GET_MDM_ST:
+        /* TODO: return modem status */
+        data[0] = 0;
+        ret = 1;
+        break;
+    case DeviceOutVendor | FTDI_SET_EVENT_CHR:
+        /* TODO: handle it */
+        s->event_chr = value;
+        break;
+    case DeviceOutVendor | FTDI_SET_ERROR_CHR:
+        /* TODO: handle it */
+        s->error_chr = value;
+        break;
+    case DeviceOutVendor | FTDI_SET_LATENCY:
+        s->latency = value;
+        break;
+    case DeviceInVendor | FTDI_GET_LATENCY:
+        data[0] = s->latency;
+        ret = 1;
+        break;
+    default:
+    fail:
+        DPRINTF("got unsupported/bogus control %x, value %x\n", request, value);
+        ret = USB_RET_STALL;
+        break;
+    }
+    return ret;
+}
+
+static int usb_serial_handle_data(USBDevice *dev, USBPacket *p)
+{
+    USBSerialState *s = (USBSerialState *)dev;
+    int ret = 0;
+    uint8_t devep = p->devep;
+    uint8_t *data = p->data;
+    int len = p->len;
+    int first_len;
+
+    switch (p->pid) {
+    case USB_TOKEN_OUT:
+        if (devep != 2)
+            goto fail;
+        qemu_chr_write(s->cs, data, len);
+        break;
+
+    case USB_TOKEN_IN:
+        if (devep != 1)
+            goto fail;
+        first_len = RECV_BUF - s->recv_ptr;
+        if (len <= 2) {
+            ret = USB_RET_NAK;
+            break;
+        }
+        /* TODO: Report serial line status */
+        *data++ = 0;
+        *data++ = 0;
+        len -= 2;
+        if (len > s->recv_used)
+            len = s->recv_used;
+        if (!len) {
+            ret = USB_RET_NAK;
+            break;
+        }
+        if (first_len > len)
+            first_len = len;
+        memcpy(data, s->recv_buf + s->recv_ptr, first_len);
+        if (len > first_len)
+            memcpy(data + first_len, s->recv_buf, len - first_len);
+        s->recv_used -= len;
+        s->recv_ptr = (s->recv_ptr + len) % RECV_BUF;
+        ret = len + 2;
+        break;
+
+    default:
+        DPRINTF("Bad token\n");
+    fail:
+        ret = USB_RET_STALL;
+        break;
+    }
+
+    return ret;
+}
+
+static void usb_serial_handle_destroy(USBDevice *dev)
+{
+    USBSerialState *s = (USBSerialState *)dev;
+
+    qemu_chr_close(s->cs);
+    qemu_free(s);
+}
+
+int usb_serial_can_read(void *opaque)
+{
+    USBSerialState *s = opaque;
+    return RECV_BUF - s->recv_used;
+}
+
+void usb_serial_read(void *opaque, const uint8_t *buf, int size)
+{
+    USBSerialState *s = opaque;
+    int first_size = RECV_BUF - s->recv_ptr;
+    if (first_size > size)
+        first_size = size;
+    memcpy(s->recv_buf + s->recv_ptr + s->recv_used, buf, first_size);
+    if (size > first_size)
+        memcpy(s->recv_buf, buf + first_size, size - first_size);
+    s->recv_used += size;
+}
+
+void usb_serial_event(void *opaque, int event)
+{
+    USBSerialState *s = opaque;
+
+    switch (event) {
+        case CHR_EVENT_BREAK:
+            /* TODO: Send Break to USB */
+            break;
+        case CHR_EVENT_FOCUS:
+            break;
+        case CHR_EVENT_RESET:
+            usb_serial_reset(s);
+            /* TODO: Reset USB port */
+            break;
+    }
+}
+
+USBDevice *usb_serial_init(const char *filename)
+{
+    USBSerialState *s;
+    CharDriverState *cdrv;
+    unsigned short vendorid = 0x0403, productid = 0xFF00;
+
+    while (*filename && *filename != ':') {
+        const char *p;
+        char *e;
+        if (strstart(filename, "vendorid=", &p)) {
+            vendorid = strtol(p, &e, 16);
+            if (e == p || (*e && *e != ',' && *e != ':')) {
+                printf("bogus vendor ID %s\n", p);
+                return NULL;
+            }
+            filename = e;
+        } else if (strstart(filename, "productid=", &p)) {
+            productid = strtol(p, &e, 16);
+            if (e == p || (*e && *e != ',' && *e != ':')) {
+                printf("bogus product ID %s\n", p);
+                return NULL;
+            }
+            filename = e;
+        } else {
+            printf("unrecognized serial USB option %s\n", filename);
+            return NULL;
+        }
+        while(*filename == ',')
+            filename++;
+    }
+    if (!*filename) {
+        printf("character device specification needed\n");
+        return NULL;
+    }
+    filename++;
+    s = qemu_mallocz(sizeof(USBSerialState));
+    if (!s)
+        return NULL;
+
+    cdrv = qemu_chr_open(filename);
+    if (!cdrv)
+        goto fail;
+    s->cs = cdrv;
+    qemu_chr_add_handlers(cdrv, usb_serial_can_read, usb_serial_read, usb_serial_event, s);
+
+    s->dev.speed = USB_SPEED_FULL;
+    s->dev.handle_packet = usb_generic_handle_packet;
+
+    s->dev.handle_reset = usb_serial_handle_reset;
+    s->dev.handle_control = usb_serial_handle_control;
+    s->dev.handle_data = usb_serial_handle_data;
+    s->dev.handle_destroy = usb_serial_handle_destroy;
+
+    s->vendorid = vendorid;
+    s->productid = productid;
+
+    snprintf(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Serial(%.16s)",
+             filename);
+
+    usb_serial_handle_reset((USBDevice *)s);
+    return (USBDevice *)s;
+ fail:
+    qemu_free(s);
+    return NULL;
+}

Modified: trunk/src/host/qemu-neo1973/hw/usb.h
===================================================================
--- trunk/src/host/qemu-neo1973/hw/usb.h	2008-01-14 20:40:58 UTC (rev 3831)
+++ trunk/src/host/qemu-neo1973/hw/usb.h	2008-01-14 23:24:21 UTC (rev 3832)
@@ -229,6 +229,9 @@
 /* usb-wacom.c */
 USBDevice *usb_wacom_init(void);
 
+/* usb-serial.c */
+USBDevice *usb_serial_init(const char *filename);
+
 /* usb ports of the VM */
 
 #define USB_INDEX_HOST  -1

Modified: trunk/src/host/qemu-neo1973/hw/vmware_vga.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/vmware_vga.c	2008-01-14 20:40:58 UTC (rev 3831)
+++ trunk/src/host/qemu-neo1973/hw/vmware_vga.c	2008-01-14 23:24:21 UTC (rev 3832)
@@ -1100,19 +1100,6 @@
     cpu_register_physical_memory(SVGA_MEM_BASE, vga_ram_size,
                     iomemtype);
 
-    register_ioport_read(SVGA_IO_BASE + SVGA_IO_MUL * SVGA_INDEX_PORT,
-                    1, 4, vmsvga_index_read, s);
-    register_ioport_write(SVGA_IO_BASE + SVGA_IO_MUL * SVGA_INDEX_PORT,
-                    1, 4, vmsvga_index_write, s);
-    register_ioport_read(SVGA_IO_BASE + SVGA_IO_MUL * SVGA_VALUE_PORT,
-                    1, 4, vmsvga_value_read, s);
-    register_ioport_write(SVGA_IO_BASE + SVGA_IO_MUL * SVGA_VALUE_PORT,
-                    1, 4, vmsvga_value_write, s);
-    register_ioport_read(SVGA_IO_BASE + SVGA_IO_MUL * SVGA_BIOS_PORT,
-                    1, 4, vmsvga_bios_read, s);
-    register_ioport_write(SVGA_IO_BASE + SVGA_IO_MUL * SVGA_BIOS_PORT,
-                    1, 4, vmsvga_bios_write, s);
-
     graphic_console_init(ds, vmsvga_update_display,
                     vmsvga_invalidate_display, vmsvga_screen_dump, s);
 
@@ -1146,6 +1133,26 @@
     return 0;
 }
 
+static void pci_vmsvga_map_ioport(PCIDevice *pci_dev, int region_num,
+                uint32_t addr, uint32_t size, int type)
+{
+    struct pci_vmsvga_state_s *d = (struct pci_vmsvga_state_s *) pci_dev;
+    struct vmsvga_state_s *s = &d->chip;
+
+    register_ioport_read(addr + SVGA_IO_MUL * SVGA_INDEX_PORT,
+                    1, 4, vmsvga_index_read, s);
+    register_ioport_write(addr + SVGA_IO_MUL * SVGA_INDEX_PORT,
+                    1, 4, vmsvga_index_write, s);
+    register_ioport_read(addr + SVGA_IO_MUL * SVGA_VALUE_PORT,
+                    1, 4, vmsvga_value_read, s);
+    register_ioport_write(addr + SVGA_IO_MUL * SVGA_VALUE_PORT,
+                    1, 4, vmsvga_value_write, s);
+    register_ioport_read(addr + SVGA_IO_MUL * SVGA_BIOS_PORT,
+                    1, 4, vmsvga_bios_read, s);
+    register_ioport_write(addr + SVGA_IO_MUL * SVGA_BIOS_PORT,
+                    1, 4, vmsvga_bios_write, s);
+}
+
 #define PCI_VENDOR_ID_VMWARE		0x15ad
 #define PCI_DEVICE_ID_VMWARE_SVGA2	0x0405
 #define PCI_DEVICE_ID_VMWARE_SVGA	0x0710
@@ -1189,6 +1196,9 @@
     s->card.config[0x2f]		= SVGA_PCI_DEVICE_ID >> 8;
     s->card.config[0x3c]		= 0xff;		/* End */
 
+    pci_register_io_region(&s->card, 0, 0x10,
+                    PCI_ADDRESS_SPACE_IO, pci_vmsvga_map_ioport);
+
     vmsvga_init(&s->chip, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
 
     register_savevm("vmware_vga", 0, 0, pci_vmsvga_save, pci_vmsvga_load, s);

Modified: trunk/src/host/qemu-neo1973/linux-user/main.c
===================================================================
--- trunk/src/host/qemu-neo1973/linux-user/main.c	2008-01-14 20:40:58 UTC (rev 3831)
+++ trunk/src/host/qemu-neo1973/linux-user/main.c	2008-01-14 23:24:21 UTC (rev 3832)
@@ -53,7 +53,8 @@
     "__init_array_end:\n"
     "__fini_array_start:\n"
     "__fini_array_end:\n"
-    ".long 0\n");
+    ".long 0\n"
+    ".previous\n");
 #endif
 
 /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so

Modified: trunk/src/host/qemu-neo1973/qemu-doc.texi
===================================================================
--- trunk/src/host/qemu-neo1973/qemu-doc.texi	2008-01-14 20:40:58 UTC (rev 3831)
+++ trunk/src/host/qemu-neo1973/qemu-doc.texi	2008-01-14 23:24:21 UTC (rev 3832)
@@ -166,6 +166,8 @@
 @item
 ENSONIQ AudioPCI ES1370 sound card
 @item
+Intel 82801AA AC97 Audio compatible sound card
+ at item
 Adlib(OPL2) - Yamaha YM3812 compatible chip
 @item
 PCI UHCI USB controller and a virtual USB hub.
@@ -173,14 +175,16 @@
 
 SMP is supported with up to 255 CPUs.
 
-Note that adlib is only available when QEMU was configured with
--enable-adlib
+Note that adlib, ac97 and gus are only available when QEMU was configured
+with --enable-adlib, --enable-ac97 or --enable-gus respectively.
 
 QEMU uses the PC BIOS from the Bochs project and the Plex86/Bochs LGPL
 VGA BIOS.
 
 QEMU uses YM3812 emulation by Tatsuyuki Satoh.
 
+QEMU uses GUS emulation(GUSEMU32) by Tibor "TS" Schütz.
+
 @c man end
 
 @node pcsys_quickstart
@@ -234,7 +238,8 @@
 @table @code
 @item file=@var{file}
 This option defines which disk image (@pxref{disk_images}) to use with
-this drive.
+this drive. If the filename contains comma, you must double it
+(for instance, "file=my,,file" to use file "my,file").
 @item if=@var{interface}
 This option defines on which type on interface the drive is connected.
 Available types are: ide, scsi, sd, mtd, floppy, pflash.
@@ -333,10 +338,18 @@
 @example
 qemu -soundhw sb16,adlib hda
 qemu -soundhw es1370 hda
+qemu -soundhw ac97 hda
 qemu -soundhw all hda
 qemu -soundhw ?
 @end example
 
+Note that Linux's i810_audio OSS kernel (for AC97) module might
+require manually specifying clocking.
+
+ at example
+modprobe i810_audio clocking=48000
+ at end example
+
 @item -localtime
 Set the real time clock to local time (the default is to UTC
 time). This option is needed to have correct date in MS-DOS or
@@ -492,8 +505,30 @@
 
 @item -usbdevice @var{devname}
 Add the USB device @var{devname}. @xref{usb_devices}.
+
+ at table @code
+
+ at item mouse
+Virtual Mouse. This will override the PS/2 mouse emulation when activated.
+
+ at item tablet
+Pointer device that uses absolute coordinates (like a touchscreen). This
+means qemu is able to report the mouse position without having to grab the
+mouse. Also overrides the PS/2 mouse emulation when activated.
+
+ at item disk:file
+Mass storage device based on file
+
+ at item host:bus.addr
+Pass through the host device identified by bus.addr (Linux only).
+
+ at item host:vendor_id:product_id
+Pass through the host device identified by vendor_id:product_id (Linux only).
+
 @end table
 
+ at end table
+
 Network options:
 
 @table @option

Modified: trunk/src/host/qemu-neo1973/target-cris/op.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-cris/op.c	2008-01-14 20:40:58 UTC (rev 3831)
+++ trunk/src/host/qemu-neo1973/target-cris/op.c	2008-01-14 23:24:21 UTC (rev 3832)
@@ -205,6 +205,7 @@
 	ccs = env->pregs[SR_CCS];
 	ccs = (ccs & 0xc0000000) | ((ccs << 12) >> 2);
 	env->pregs[SR_CCS] = ccs;
+	RETURN();
 }
 void OPPROTO op_ccs_rshift (void)
 {
@@ -214,6 +215,7 @@
 	ccs = env->pregs[SR_CCS];
 	ccs = (ccs & 0xc0000000) | (ccs >> 10);
 	env->pregs[SR_CCS] = ccs;
+	RETURN();
 }
 
 void OPPROTO op_setf (void)

Modified: trunk/src/host/qemu-neo1973/target-cris/translate.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-cris/translate.c	2008-01-14 20:40:58 UTC (rev 3831)
+++ trunk/src/host/qemu-neo1973/target-cris/translate.c	2008-01-14 23:24:21 UTC (rev 3832)
@@ -110,15 +110,6 @@
 	unsigned int mode;
 	unsigned int postinc;
 
-
-	struct
-	{
-		int op;
-		int size;
-		unsigned int mask;
-	} cc_state[3];
-	int cc_i;
-
 	int update_cc;
 	int cc_op;
 	int cc_size;
@@ -183,6 +174,10 @@
 	gen_op_movl_T0_im(32);
 }
 
+static void gen_movl_T0_p0(void) {
+	gen_op_movl_T0_im(0);
+}
+
 static void gen_ccs_read(void) {
 	gen_op_movl_T0_p13();
 }
@@ -209,7 +204,7 @@
 };
 static GenOpFunc *gen_movl_T0_preg[16] =
 {
-	gen_op_movl_T0_p0,
+	gen_movl_T0_p0,
 	gen_vr_read,
 	gen_op_movl_T0_p2, gen_op_movl_T0_p3,
 	gen_op_movl_T0_p4, gen_op_movl_T0_p5,
@@ -345,6 +340,8 @@
 {
 	uint32_t ovl;
 
+	/* Check if we need to evaluate the condition codes due to 
+	   CC overlaying.  */
 	ovl = (dc->cc_mask ^ mask) & ~mask;
 	if (ovl) {
 		/* TODO: optimize this case. It trigs all the time.  */
@@ -987,7 +984,6 @@
 {
 	dc->op1 = EXTRACT_FIELD(dc->ir, 0, 4);
 	DIS(fprintf (logfile, "btstq %u, $r%d\n", dc->op1, dc->op2));
-	cris_evaluate_flags(dc);
 	cris_cc_mask(dc, CC_MASK_NZ);
 	gen_movl_T0_reg[dc->op2]();
 	gen_op_movl_T1_im(dc->op1);
@@ -1333,7 +1329,6 @@
 {
 	DIS(fprintf (logfile, "btst $r%u, $r%u\n",
 		    dc->op1, dc->op2));
-	cris_evaluate_flags(dc);
 	cris_cc_mask(dc, CC_MASK_NZ);
 	dec_prep_alu_r(dc, dc->op1, dc->op2, 4, 0);
 	crisv32_alu_op(dc, CC_OP_BTST, dc->op2, 4);
@@ -1518,8 +1513,14 @@
 {
 	DIS(fprintf (logfile, "move $p%u, $r%u\n", dc->op1, dc->op2));
 	cris_cc_mask(dc, 0);
-	gen_movl_T0_preg[dc->op2]();
-	gen_op_movl_T1_T0();
+	/* Support register 0 is hardwired to zero. 
+	   Treat it specially. */
+	if (dc->op2 == 0)
+		gen_op_movl_T1_im(0);
+	else {
+		gen_movl_T0_preg[dc->op2]();
+		gen_op_movl_T1_T0();
+	}
 	crisv32_alu_op(dc, CC_OP_MOVE, dc->op1, preg_sizes[dc->op2]);
 	return 2;
 }
@@ -1846,13 +1847,21 @@
 
 	memsize = preg_sizes[dc->op2];
 
-	DIS(fprintf (logfile, "move.%d $p%u, [$r%u%s\n",
-		     memsize, dc->op2, dc->op1, dc->postinc ? "+]" : "]"));
+	DIS(fprintf (logfile, "move.%c $p%u, [$r%u%s\n",
+		     memsize_char(memsize), 
+		     dc->op2, dc->op1, dc->postinc ? "+]" : "]"));
 
 	cris_cc_mask(dc, 0);
-	/* prepare store.  */
-	gen_movl_T0_preg[dc->op2]();
-	gen_op_movl_T1_T0();
+	/* prepare store. Address in T0, value in T1.  */
+	/* Support register 0 is hardwired to zero. 
+	   Treat it specially. */
+	if (dc->op2 == 0)
+		gen_op_movl_T1_im(0);
+	else
+	{
+		gen_movl_T0_preg[dc->op2]();
+		gen_op_movl_T1_T0();
+	}
 	gen_movl_T0_reg[dc->op1]();
 	gen_store_T0_T1(dc, memsize);
 	if (dc->postinc)

Modified: trunk/src/host/qemu-neo1973/target-mips/exec.h
===================================================================
--- trunk/src/host/qemu-neo1973/target-mips/exec.h	2008-01-14 20:40:58 UTC (rev 3831)
+++ trunk/src/host/qemu-neo1973/target-mips/exec.h	2008-01-14 23:24:21 UTC (rev 3832)
@@ -258,7 +258,7 @@
     if (env->CP0_Status & (1 << CP0St_FR))
         env->hflags |= MIPS_HFLAG_F64;
     if (env->insn_flags & ISA_MIPS32R2) {
-        if (env->fpu->fcr0 & FCR0_F64)
+        if (env->fpu->fcr0 & (1 << FCR0_F64))
             env->hflags |= MIPS_HFLAG_COP1X;
     } else if (env->insn_flags & ISA_MIPS32) {
         if (env->hflags & MIPS_HFLAG_64)

Modified: trunk/src/host/qemu-neo1973/target-mips/op_helper.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-mips/op_helper.c	2008-01-14 20:40:58 UTC (rev 3831)
+++ trunk/src/host/qemu-neo1973/target-mips/op_helper.c	2008-01-14 23:24:21 UTC (rev 3832)
@@ -1250,8 +1250,8 @@
 void do_cmpabs_d_ ## op (long cc)              \
 {                                              \
     int c;                                     \
-    FDT0 = float64_chs(FDT0);                  \
-    FDT1 = float64_chs(FDT1);                  \
+    FDT0 = float64_abs(FDT0);                  \
+    FDT1 = float64_abs(FDT1);                  \
     c = cond;                                  \
     update_fcr31();                            \
     if (c)                                     \

Modified: trunk/src/host/qemu-neo1973/vl.c
===================================================================
--- trunk/src/host/qemu-neo1973/vl.c	2008-01-14 20:40:58 UTC (rev 3831)
+++ trunk/src/host/qemu-neo1973/vl.c	2008-01-14 23:24:21 UTC (rev 3832)
@@ -233,7 +233,10 @@
 struct bt_piconet_s *local_piconet;
 struct modem_ops_s modem_ops;
 int nb_drives_opt;
-char drives_opt[MAX_DRIVES][1024];
+struct drive_opt {
+    const char *file;
+    char opt[1024];
+} drives_opt[MAX_DRIVES];
 
 static CPUState *cur_cpu;
 static CPUState *next_cpu;
@@ -2266,45 +2269,33 @@
 #endif
     tcgetattr (fd, &tty);
 
-    switch(speed) {
-    case 50:
+#define MARGIN 1.1
+    if (speed <= 50 * MARGIN)
         spd = B50;
-        break;
-    case 75:
+    else if (speed <= 75 * MARGIN)
         spd = B75;
-        break;
-    case 300:
+    else if (speed <= 300 * MARGIN)
         spd = B300;
-        break;
-    case 600:
+    else if (speed <= 600 * MARGIN)
         spd = B600;
-        break;
-    case 1200:
+    else if (speed <= 1200 * MARGIN)
         spd = B1200;
-        break;
-    case 2400:
+    else if (speed <= 2400 * MARGIN)
         spd = B2400;
-        break;
-    case 4800:
+    else if (speed <= 4800 * MARGIN)
         spd = B4800;
-        break;
-    case 9600:
+    else if (speed <= 9600 * MARGIN)
         spd = B9600;
-        break;
-    case 19200:
+    else if (speed <= 19200 * MARGIN)
         spd = B19200;
-        break;
-    case 38400:
+    else if (speed <= 38400 * MARGIN)
         spd = B38400;
-        break;
-    case 57600:
+    else if (speed <= 57600 * MARGIN)
         spd = B57600;
-        break;
-    default:
-    case 115200:
+    else if (speed <= 115200 * MARGIN)
         spd = B115200;
-        break;
-    }
+    else
+        spd = B115200;
 
     cfsetispeed(&tty, spd);
     cfsetospeed(&tty, spd);
@@ -3801,30 +3792,38 @@
 
 char smb_dir[1024];
 
-static void smb_exit(void)
+static void erase_dir(char *dir_name)
 {
     DIR *d;
     struct dirent *de;
     char filename[1024];
 
     /* erase all the files in the directory */
-    d = opendir(smb_dir);
-    for(;;) {
-        de = readdir(d);
-        if (!de)
-            break;
-        if (strcmp(de->d_name, ".") != 0 &&
-            strcmp(de->d_name, "..") != 0) {
-            snprintf(filename, sizeof(filename), "%s/%s",
-                     smb_dir, de->d_name);
-            unlink(filename);
+    if ((d = opendir(dir_name)) != 0) {
+        for(;;) {
+            de = readdir(d);
+            if (!de)
+                break;
+            if (strcmp(de->d_name, ".") != 0 &&
+                strcmp(de->d_name, "..") != 0) {
+                snprintf(filename, sizeof(filename), "%s/%s",
+                         smb_dir, de->d_name);
+                if (unlink(filename) != 0)  /* is it a directory? */
+                    erase_dir(filename);
+            }
         }
+        closedir(d);
+        rmdir(dir_name);
     }
-    closedir(d);
-    rmdir(smb_dir);
 }
 
 /* automatic user mode samba server configuration */
+static void smb_exit(void)
+{
+    erase_dir(smb_dir);
+}
+
+/* automatic user mode samba server configuration */
 static void net_slirp_smb(const char *exported_dir)
 {
     char smb_conf[1024];
@@ -4610,24 +4609,33 @@
 
 }
 
-static const char *get_word(char *buf, int buf_size, const char *p)
+static const char *get_opt_name(char *buf, int buf_size, const char *p)
 {
     char *q;
-    int substring;
 
-    substring = 0;
     q = buf;
+    while (*p != '\0' && *p != '=') {
+        if (q && (q - buf) < buf_size - 1)
+            *q++ = *p;
+        p++;
+    }
+    if (q)
+        *q = '\0';
+
+    return p;
+}
+
+static const char *get_opt_value(char *buf, int buf_size, const char *p)
+{
+    char *q;
+
+    q = buf;
     while (*p != '\0') {
-        if (*p == '\\') {
-            p++;
-            if (*p == '\0')
+        if (*p == ',') {
+            if (*(p + 1) != ',')
                 break;
-        } else if (*p == '\"') {
-            substring = !substring;
             p++;
-            continue;
-        } else if (!substring && (*p == ',' || *p == '='))
-            break;
+        }
         if (q && (q - buf) < buf_size - 1)
             *q++ = *p;
         p++;
@@ -4646,15 +4654,15 @@
 
     p = str;
     for(;;) {
-        p = get_word(option, sizeof(option), p);
+        p = get_opt_name(option, sizeof(option), p);
         if (*p != '=')
             break;
         p++;
         if (!strcmp(tag, option)) {
-            (void)get_word(buf, buf_size, p);
+            (void)get_opt_value(buf, buf_size, p);
             return strlen(buf);
         } else {
-            p = get_word(NULL, 0, p);
+            p = get_opt_value(NULL, 0, p);
         }
         if (*p != ',')
             break;
@@ -4671,7 +4679,7 @@
 
     p = str;
     for(;;) {
-        p = get_word(buf, buf_size, p);
+        p = get_opt_name(buf, buf_size, p);
         if (*p != '=')
             return -1;
         p++;
@@ -4680,7 +4688,7 @@
                 break;
         if (params[i] == NULL)
             return -1;
-        p = get_word(NULL, 0, p);
+        p = get_opt_value(NULL, 0, p);
         if (*p != ',')
             break;
         p++;
@@ -4839,18 +4847,18 @@
     }
 }
 
-#define HD_ALIAS "file=\"%s\",index=%d,media=disk"
+#define HD_ALIAS "index=%d,media=disk"
 #ifdef TARGET_PPC
 #define CDROM_ALIAS "index=1,media=cdrom"
 #else
 #define CDROM_ALIAS "index=2,media=cdrom"
 #endif
 #define FD_ALIAS "index=%d,if=floppy"
-#define PFLASH_ALIAS "file=\"%s\",if=pflash"
-#define MTD_ALIAS "file=\"%s\",if=mtd"
+#define PFLASH_ALIAS "if=pflash"
+#define MTD_ALIAS "if=mtd"
 #define SD_ALIAS "index=0,if=sd"
 
-static int drive_add(const char *fmt, ...)
+static int drive_add(const char *file, const char *fmt, ...)
 {
     va_list ap;
 
@@ -4859,8 +4867,10 @@
         exit(1);
     }
 
+    drives_opt[nb_drives_opt].file = file;
     va_start(ap, fmt);
-    vsnprintf(drives_opt[nb_drives_opt], sizeof(drives_opt[0]), fmt, ap);
+    vsnprintf(drives_opt[nb_drives_opt].opt,
+              sizeof(drives_opt[0].opt), fmt, ap);
     va_end(ap);
 
     return nb_drives_opt++;
@@ -4895,7 +4905,8 @@
     return max_bus;
 }
 
-static int drive_init(const char *str, int snapshot, QEMUMachine *machine)
+static int drive_init(struct drive_opt *arg, int snapshot,
+                      QEMUMachine *machine)
 {
     char buf[128];
     char file[1024];
@@ -4910,6 +4921,7 @@
     int index;
     int cache;
     int bdrv_flags;
+    char *str = arg->opt;
     char *params[] = { "bus", "unit", "if", "index", "cyls", "heads",
                        "secs", "trans", "media", "snapshot", "file",
                        "cache", NULL };
@@ -5080,7 +5092,10 @@
         }
     }
 
-    get_param_value(file, sizeof(file), "file", str);
+    if (arg->file == NULL)
+        get_param_value(file, sizeof(file), "file", str);
+    else
+        pstrcpy(file, sizeof(file), arg->file);
 
     /* compute bus and unit according index */
 
@@ -5281,6 +5296,8 @@
         dev = usb_net_init(&nd_table[nr]);
     } else if (!strcmp(devname, "wacom-tablet")) {
         dev = usb_wacom_init();
+    } else if (strstart(devname, "serial:", &p)) {
+        dev = usb_serial_init(p);
     } else {
         return -1;
     }
@@ -8233,7 +8250,17 @@
     },
 #endif
 
+#ifdef CONFIG_AC97
     {
+        "ac97",
+        "Intel 82801AA AC97 Audio",
+        0,
+        0,
+        { .init_pci = ac97_init }
+    },
+#endif
+
+    {
         "es1370",
         "ENSONIQ AudioPCI ES1370",
         0,
@@ -8424,7 +8451,7 @@
             break;
         r = argv[optind];
         if (r[0] != '-') {
-	    hda_index = drive_add(HD_ALIAS, argv[optind++], 0);
+	    hda_index = drive_add(argv[optind++], HD_ALIAS, 0);
         } else {
             const QEMUOption *popt;
 
@@ -8485,11 +8512,11 @@
                 break;
             case QEMU_OPTION_hda:
                 if (cyls == 0)
-                    hda_index = drive_add(HD_ALIAS, optarg, 0);
+                    hda_index = drive_add(optarg, HD_ALIAS, 0);
                 else
-                    hda_index = drive_add(HD_ALIAS
+                    hda_index = drive_add(optarg, HD_ALIAS
 			     ",cyls=%d,heads=%d,secs=%d%s",
-                             optarg, 0, cyls, heads, secs,
+                             0, cyls, heads, secs,
                              translation == BIOS_ATA_TRANSLATION_LBA ?
                                  ",trans=lba" :
                              translation == BIOS_ATA_TRANSLATION_NONE ?
@@ -8498,19 +8525,19 @@
             case QEMU_OPTION_hdb:
             case QEMU_OPTION_hdc:
             case QEMU_OPTION_hdd:
-		drive_add(HD_ALIAS, optarg, popt->index - QEMU_OPTION_hda);
+                drive_add(optarg, HD_ALIAS, popt->index - QEMU_OPTION_hda);
                 break;
             case QEMU_OPTION_drive:
-                drive_add("%s", optarg);
+                drive_add(NULL, "%s", optarg);
 	        break;
             case QEMU_OPTION_mtdblock:
-	        drive_add(MTD_ALIAS, optarg);
+                drive_add(optarg, MTD_ALIAS);
                 break;
             case QEMU_OPTION_sd:
-                drive_add("file=\"%s\"," SD_ALIAS, optarg);
+                drive_add(optarg, SD_ALIAS);
                 break;
             case QEMU_OPTION_pflash:
-	        drive_add(PFLASH_ALIAS, optarg);
+                drive_add(optarg, PFLASH_ALIAS);
                 break;
             case QEMU_OPTION_snapshot:
                 snapshot = 1;
@@ -8550,12 +8577,10 @@
                         exit(1);
                     }
 		    if (hda_index != -1)
-		        snprintf(drives_opt[hda_index] +
-			         strlen(drives_opt[hda_index]),
-			         sizeof(drives_opt[0]) -
-				 strlen(drives_opt[hda_index]),
-		                 ",cyls=%d,heads=%d,secs=%d%s",
-			         cyls, heads, secs,
+                        snprintf(drives_opt[hda_index].opt,
+                                 sizeof(drives_opt[hda_index].opt),
+                                 HD_ALIAS ",cyls=%d,heads=%d,secs=%d%s",
+                                 0, cyls, heads, secs,
 			         translation == BIOS_ATA_TRANSLATION_LBA ?
 			     	    ",trans=lba" :
 			         translation == BIOS_ATA_TRANSLATION_NONE ?
@@ -8578,7 +8603,7 @@
                 kernel_cmdline = optarg;
                 break;
             case QEMU_OPTION_cdrom:
-		drive_add("file=\"%s\"," CDROM_ALIAS, optarg);
+                drive_add(optarg, CDROM_ALIAS);
                 break;
             case QEMU_OPTION_boot:
                 boot_devices = optarg;
@@ -8613,8 +8638,7 @@
                 break;
             case QEMU_OPTION_fda:
             case QEMU_OPTION_fdb:
-		drive_add("file=\"%s\"," FD_ALIAS, optarg,
-		          popt->index - QEMU_OPTION_fda);
+                drive_add(optarg, FD_ALIAS, popt->index - QEMU_OPTION_fda);
                 break;
 #ifdef TARGET_I386
             case QEMU_OPTION_no_fd_bootchk:
@@ -8896,6 +8920,7 @@
 #ifdef TARGET_ARM
             case QEMU_OPTION_old_param:
                 old_param = 1;
+                break;
 #endif
             case QEMU_OPTION_clock:
                 configure_alarms(optarg);
@@ -9096,22 +9121,22 @@
     /* we always create the cdrom drive, even if no disk is there */
 
     if (nb_drives_opt < MAX_DRIVES)
-        drive_add(CDROM_ALIAS);
+        drive_add(NULL, CDROM_ALIAS);
 
     /* we always create at least one floppy */
 
     if (nb_drives_opt < MAX_DRIVES)
-        drive_add(FD_ALIAS, 0);
+        drive_add(NULL, FD_ALIAS, 0);
 
     /* we always create one sd slot, even if no card is in it */
 
     if (nb_drives_opt < MAX_DRIVES)
-        drive_add(SD_ALIAS);
+        drive_add(NULL, SD_ALIAS);
 
     /* open the virtual block devices */
 
     for(i = 0; i < nb_drives_opt; i++)
-        if (drive_init(drives_opt[i], snapshot, machine) == -1)
+        if (drive_init(&drives_opt[i], snapshot, machine) == -1)
 	    exit(1);
 
     register_savevm("timer", 0, 2, timer_save, timer_load, NULL);

Modified: trunk/src/host/qemu-neo1973/vnc.c
===================================================================
--- trunk/src/host/qemu-neo1973/vnc.c	2008-01-14 20:40:58 UTC (rev 3831)
+++ trunk/src/host/qemu-neo1973/vnc.c	2008-01-14 23:24:21 UTC (rev 3832)
@@ -506,6 +506,8 @@
 	int saved_offset;
 	int has_dirty = 0;
 
+        vga_hw_update();
+
         vnc_set_bits(width_mask, (vs->width / 16), VNC_DIRTY_WORDS);
 
 	/* Walk through the dirty map and eliminate tiles that
@@ -580,22 +582,11 @@
 	vnc_flush(vs);
 
     }
-    qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL);
-}
 
-static void vnc_timer_init(VncState *vs)
-{
-    if (vs->timer == NULL) {
-	vs->timer = qemu_new_timer(rt_clock, vnc_update_client, vs);
-	qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock));
+    if (vs->csock != -1) {
+        qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL);
     }
-}
 
-static void vnc_dpy_refresh(DisplayState *ds)
-{
-    VncState *vs = ds->opaque;
-    vnc_timer_init(vs);
-    vga_hw_update();
 }
 
 static int vnc_listen_poll(void *opaque)
@@ -1913,6 +1904,9 @@
     struct sockaddr_in addr;
     socklen_t addrlen = sizeof(addr);
 
+    /* Catch-up */
+    vga_hw_update();
+
     vs->csock = accept(vs->lsock, (struct sockaddr *)&addr, &addrlen);
     if (vs->csock != -1) {
 	VNC_DEBUG("New client on socket %d\n", vs->csock);
@@ -1926,6 +1920,7 @@
 	vs->has_resize = 0;
 	vs->has_hextile = 0;
 	vs->ds->dpy_copy = NULL;
+        vnc_update_client(vs);
     }
 }
 
@@ -1959,10 +1954,12 @@
     if (!vs->kbd_layout)
 	exit(1);
 
+    vs->timer = qemu_new_timer(rt_clock, vnc_update_client, vs);
+
     vs->ds->data = NULL;
     vs->ds->dpy_update = vnc_dpy_update;
     vs->ds->dpy_resize = vnc_dpy_resize;
-    vs->ds->dpy_refresh = vnc_dpy_refresh;
+    vs->ds->dpy_refresh = NULL;
 
     memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row));
 





More information about the commitlog mailing list