Commit ca9cc28c62a2c2877186569f4ab0cf1034502a73

Authored by balrog
1 parent b34d259a

pthreads-based audio and miscellaneous audio clean-up (malc).

ESD support (malc, Frederick Reeve).


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3917 c046a42c-6fe2-441c-8c8c-71466251a162
Makefile
... ... @@ -73,6 +73,7 @@ AUDIO_OBJS += ossaudio.o
73 73 endif
74 74 ifdef CONFIG_COREAUDIO
75 75 AUDIO_OBJS += coreaudio.o
  76 +AUDIO_PT = yes
76 77 endif
77 78 ifdef CONFIG_ALSA
78 79 AUDIO_OBJS += alsaaudio.o
... ... @@ -84,6 +85,17 @@ ifdef CONFIG_FMOD
84 85 AUDIO_OBJS += fmodaudio.o
85 86 audio/audio.o audio/fmodaudio.o: CPPFLAGS := -I$(CONFIG_FMOD_INC) $(CPPFLAGS)
86 87 endif
  88 +ifdef CONFIG_ESD
  89 +AUDIO_PT = yes
  90 +AUDIO_PT_INT = yes
  91 +AUDIO_OBJS += esdaudio.o
  92 +endif
  93 +ifdef AUDIO_PT
  94 +LDFLAGS += -pthread
  95 +endif
  96 +ifdef AUDIO_PT_INT
  97 +AUDIO_OBJS += audio_pt_int.o
  98 +endif
87 99 AUDIO_OBJS+= wavcapture.o
88 100 OBJS+=$(addprefix audio/, $(AUDIO_OBJS))
89 101  
... ...
Makefile.target
... ... @@ -404,6 +404,9 @@ endif
404 404 ifdef CONFIG_ALSA
405 405 LIBS += -lasound
406 406 endif
  407 +ifdef CONFIG_ESD
  408 +LIBS += -lesd
  409 +endif
407 410 ifdef CONFIG_DSOUND
408 411 LIBS += -lole32 -ldxguid
409 412 endif
... ... @@ -412,6 +415,9 @@ LIBS += $(CONFIG_FMOD_LIB)
412 415 endif
413 416  
414 417 SOUND_HW = sb16.o es1370.o
  418 +ifdef CONFIG_AC97
  419 +SOUND_HW += ac97.o
  420 +endif
415 421 ifdef CONFIG_ADLIB
416 422 SOUND_HW += fmopl.o adlib.o
417 423 endif
... ... @@ -641,8 +647,9 @@ endif
641 647  
642 648 ifeq (1, 0)
643 649 audio.o sdlaudio.o dsoundaudio.o ossaudio.o wavaudio.o noaudio.o \
644   -fmodaudio.o alsaaudio.o mixeng.o sb16.o es1370.o gus.o adlib.o: \
645   -CFLAGS := $(CFLAGS) -Wall -Werror -W -Wsign-compare
  650 +fmodaudio.o alsaaudio.o mixeng.o sb16.o es1370.o ac97.o gus.o adlib.o \
  651 +esdaudio.o audio_pt_int.o: \
  652 +CFLAGS := $(CFLAGS) -O0 -g -Wall -Werror -W -Wsign-compare -Wno-unused
646 653 endif
647 654  
648 655 # Include automatically generated dependency files
... ...
audio/alsaaudio.c
... ... @@ -86,9 +86,9 @@ static struct {
86 86 };
87 87  
88 88 struct alsa_params_req {
89   - unsigned int freq;
90   - audfmt_e fmt;
91   - unsigned int nchannels;
  89 + int freq;
  90 + snd_pcm_format_t fmt;
  91 + int nchannels;
92 92 unsigned int buffer_size;
93 93 unsigned int period_size;
94 94 };
... ... @@ -96,6 +96,7 @@ struct alsa_params_req {
96 96 struct alsa_params_obt {
97 97 int freq;
98 98 audfmt_e fmt;
  99 + int endianness;
99 100 int nchannels;
100 101 snd_pcm_uframes_t samples;
101 102 };
... ... @@ -143,7 +144,7 @@ static int alsa_write (SWVoiceOut *sw, void *buf, int len)
143 144 return audio_pcm_sw_write (sw, buf, len);
144 145 }
145 146  
146   -static int aud_to_alsafmt (audfmt_e fmt)
  147 +static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt)
147 148 {
148 149 switch (fmt) {
149 150 case AUD_FMT_S8:
... ... @@ -173,7 +174,8 @@ static int aud_to_alsafmt (audfmt_e fmt)
173 174 }
174 175 }
175 176  
176   -static int alsa_to_audfmt (int alsafmt, audfmt_e *fmt, int *endianness)
  177 +static int alsa_to_audfmt (snd_pcm_format_t alsafmt, audfmt_e *fmt,
  178 + int *endianness)
177 179 {
178 180 switch (alsafmt) {
179 181 case SND_PCM_FORMAT_S8:
... ... @@ -234,7 +236,6 @@ static int alsa_to_audfmt (int alsafmt, audfmt_e *fmt, int *endianness)
234 236 return 0;
235 237 }
236 238  
237   -#if defined DEBUG_MISMATCHES || defined DEBUG
238 239 static void alsa_dump_info (struct alsa_params_req *req,
239 240 struct alsa_params_obt *obt)
240 241 {
... ... @@ -248,7 +249,6 @@ static void alsa_dump_info (struct alsa_params_req *req,
248 249 req->buffer_size, req->period_size);
249 250 dolog ("obtained: samples %ld\n", obt->samples);
250 251 }
251   -#endif
252 252  
253 253 static void alsa_set_threshold (snd_pcm_t *handle, snd_pcm_uframes_t threshold)
254 254 {
... ... @@ -291,6 +291,7 @@ static int alsa_open (int in, struct alsa_params_req *req,
291 291 unsigned int period_size, buffer_size;
292 292 snd_pcm_uframes_t obt_buffer_size;
293 293 const char *typ = in ? "ADC" : "DAC";
  294 + snd_pcm_format_t obtfmt;
294 295  
295 296 freq = req->freq;
296 297 period_size = req->period_size;
... ... @@ -327,9 +328,8 @@ static int alsa_open (int in, struct alsa_params_req *req,
327 328 }
328 329  
329 330 err = snd_pcm_hw_params_set_format (handle, hw_params, req->fmt);
330   - if (err < 0) {
  331 + if (err < 0 && conf.verbose) {
331 332 alsa_logerr2 (err, typ, "Failed to set format %d\n", req->fmt);
332   - goto err;
333 333 }
334 334  
335 335 err = snd_pcm_hw_params_set_rate_near (handle, hw_params, &freq, 0);
... ... @@ -494,6 +494,17 @@ static int alsa_open (int in, struct alsa_params_req *req,
494 494 goto err;
495 495 }
496 496  
  497 + err = snd_pcm_hw_params_get_format (hw_params, &obtfmt);
  498 + if (err < 0) {
  499 + alsa_logerr2 (err, typ, "Failed to get format\n");
  500 + goto err;
  501 + }
  502 +
  503 + if (alsa_to_audfmt (obtfmt, &obt->fmt, &obt->endianness)) {
  504 + dolog ("Invalid format was returned %d\n", obtfmt);
  505 + goto err;
  506 + }
  507 +
497 508 err = snd_pcm_prepare (handle);
498 509 if (err < 0) {
499 510 alsa_logerr2 (err, typ, "Could not prepare handle %p\n", handle);
... ... @@ -504,28 +515,41 @@ static int alsa_open (int in, struct alsa_params_req *req,
504 515 snd_pcm_uframes_t threshold;
505 516 int bytes_per_sec;
506 517  
507   - bytes_per_sec = freq
508   - << (nchannels == 2)
509   - << (req->fmt == AUD_FMT_S16 || req->fmt == AUD_FMT_U16);
  518 + bytes_per_sec = freq << (nchannels == 2);
  519 +
  520 + switch (obt->fmt) {
  521 + case AUD_FMT_S8:
  522 + case AUD_FMT_U8:
  523 + break;
  524 +
  525 + case AUD_FMT_S16:
  526 + case AUD_FMT_U16:
  527 + bytes_per_sec <<= 1;
  528 + break;
  529 +
  530 + case AUD_FMT_S32:
  531 + case AUD_FMT_U32:
  532 + bytes_per_sec <<= 2;
  533 + break;
  534 + }
510 535  
511 536 threshold = (conf.threshold * bytes_per_sec) / 1000;
512 537 alsa_set_threshold (handle, threshold);
513 538 }
514 539  
515   - obt->fmt = req->fmt;
516 540 obt->nchannels = nchannels;
517 541 obt->freq = freq;
518 542 obt->samples = obt_buffer_size;
  543 +
519 544 *handlep = handle;
520 545  
521   -#if defined DEBUG_MISMATCHES || defined DEBUG
522   - if (obt->fmt != req->fmt ||
523   - obt->nchannels != req->nchannels ||
524   - obt->freq != req->freq) {
525   - dolog ("Audio paramters mismatch for %s\n", typ);
  546 + if (conf.verbose &&
  547 + (obt->fmt != req->fmt ||
  548 + obt->nchannels != req->nchannels ||
  549 + obt->freq != req->freq)) {
  550 + dolog ("Audio paramters for %s\n", typ);
526 551 alsa_dump_info (req, obt);
527 552 }
528   -#endif
529 553  
530 554 #ifdef DEBUG
531 555 alsa_dump_info (req, obt);
... ... @@ -665,9 +689,6 @@ static int alsa_init_out (HWVoiceOut *hw, audsettings_t *as)
665 689 ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
666 690 struct alsa_params_req req;
667 691 struct alsa_params_obt obt;
668   - audfmt_e effective_fmt;
669   - int endianness;
670   - int err;
671 692 snd_pcm_t *handle;
672 693 audsettings_t obt_as;
673 694  
... ... @@ -681,16 +702,10 @@ static int alsa_init_out (HWVoiceOut *hw, audsettings_t *as)
681 702 return -1;
682 703 }
683 704  
684   - err = alsa_to_audfmt (obt.fmt, &effective_fmt, &endianness);
685   - if (err) {
686   - alsa_anal_close (&handle);
687   - return -1;
688   - }
689   -
690 705 obt_as.freq = obt.freq;
691 706 obt_as.nchannels = obt.nchannels;
692   - obt_as.fmt = effective_fmt;
693   - obt_as.endianness = endianness;
  707 + obt_as.fmt = obt.fmt;
  708 + obt_as.endianness = obt.endianness;
694 709  
695 710 audio_pcm_init_info (&hw->info, &obt_as);
696 711 hw->samples = obt.samples;
... ... @@ -751,9 +766,6 @@ static int alsa_init_in (HWVoiceIn *hw, audsettings_t *as)
751 766 ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
752 767 struct alsa_params_req req;
753 768 struct alsa_params_obt obt;
754   - int endianness;
755   - int err;
756   - audfmt_e effective_fmt;
757 769 snd_pcm_t *handle;
758 770 audsettings_t obt_as;
759 771  
... ... @@ -767,16 +779,10 @@ static int alsa_init_in (HWVoiceIn *hw, audsettings_t *as)
767 779 return -1;
768 780 }
769 781  
770   - err = alsa_to_audfmt (obt.fmt, &effective_fmt, &endianness);
771   - if (err) {
772   - alsa_anal_close (&handle);
773   - return -1;
774   - }
775   -
776 782 obt_as.freq = obt.freq;
777 783 obt_as.nchannels = obt.nchannels;
778   - obt_as.fmt = effective_fmt;
779   - obt_as.endianness = endianness;
  784 + obt_as.fmt = obt.fmt;
  785 + obt_as.endianness = obt.endianness;
780 786  
781 787 audio_pcm_init_info (&hw->info, &obt_as);
782 788 hw->samples = obt.samples;
... ...
audio/audio.c
... ... @@ -56,6 +56,9 @@ static struct audio_driver *drvtab[] = {
56 56 #ifdef CONFIG_SDL
57 57 &sdl_audio_driver,
58 58 #endif
  59 +#ifdef CONFIG_ESD
  60 + &esd_audio_driver,
  61 +#endif
59 62 &no_audio_driver,
60 63 &wav_audio_driver
61 64 };
... ... @@ -414,7 +417,7 @@ static void audio_print_options (const char *prefix,
414 417 {
415 418 audfmt_e *fmtp = opt->valp;
416 419 printf (
417   - "format, %s = %s, (one of: U8 S8 U16 S16)\n",
  420 + "format, %s = %s, (one of: U8 S8 U16 S16 U32 S32)\n",
418 421 state,
419 422 audio_audfmt_to_string (*fmtp)
420 423 );
... ...
audio/audio_int.h
... ... @@ -202,6 +202,7 @@ extern struct audio_driver fmod_audio_driver;
202 202 extern struct audio_driver alsa_audio_driver;
203 203 extern struct audio_driver coreaudio_audio_driver;
204 204 extern struct audio_driver dsound_audio_driver;
  205 +extern struct audio_driver esd_audio_driver;
205 206 extern volume_t nominal_volume;
206 207  
207 208 void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as);
... ...
audio/audio_pt_int.c 0 โ†’ 100644
  1 +#include "qemu-common.h"
  2 +#include "audio.h"
  3 +
  4 +#define AUDIO_CAP "audio-pt"
  5 +
  6 +#include "audio_int.h"
  7 +#include "audio_pt_int.h"
  8 +
  9 +static void logerr (struct audio_pt *pt, int err, const char *fmt, ...)
  10 +{
  11 + va_list ap;
  12 +
  13 + va_start (ap, fmt);
  14 + AUD_vlog (pt->drv, fmt, ap);
  15 + va_end (ap);
  16 +
  17 + AUD_log (NULL, "\n");
  18 + AUD_log (pt->drv, "Reason: %s\n", strerror (err));
  19 +}
  20 +
  21 +int audio_pt_init (struct audio_pt *p, void *(*func) (void *),
  22 + void *opaque, const char *drv, const char *cap)
  23 +{
  24 + int err, err2;
  25 + const char *efunc;
  26 +
  27 + p->drv = drv;
  28 +
  29 + err = pthread_mutex_init (&p->mutex, NULL);
  30 + if (err) {
  31 + efunc = "pthread_mutex_init";
  32 + goto err0;
  33 + }
  34 +
  35 + err = pthread_cond_init (&p->cond, NULL);
  36 + if (err) {
  37 + efunc = "pthread_cond_init";
  38 + goto err1;
  39 + }
  40 +
  41 + err = pthread_create (&p->thread, NULL, func, opaque);
  42 + if (err) {
  43 + efunc = "pthread_create";
  44 + goto err2;
  45 + }
  46 +
  47 + return 0;
  48 +
  49 + err2:
  50 + err2 = pthread_cond_destroy (&p->cond);
  51 + if (err2) {
  52 + logerr (p, err2, "%s(%s): pthread_cond_destroy failed", cap, AUDIO_FUNC);
  53 + }
  54 +
  55 + err1:
  56 + err2 = pthread_mutex_destroy (&p->mutex);
  57 + if (err2) {
  58 + logerr (p, err2, "%s(%s): pthread_mutex_destroy failed", cap, AUDIO_FUNC);
  59 + }
  60 +
  61 + err0:
  62 + logerr (p, err, "%s(%s): %s failed", cap, AUDIO_FUNC, efunc);
  63 + return -1;
  64 +}
  65 +
  66 +int audio_pt_fini (struct audio_pt *p, const char *cap)
  67 +{
  68 + int err, ret = 0;
  69 +
  70 + err = pthread_cond_destroy (&p->cond);
  71 + if (err) {
  72 + logerr (p, err, "%s(%s): pthread_cond_destroy failed", cap, AUDIO_FUNC);
  73 + ret = -1;
  74 + }
  75 +
  76 + err = pthread_mutex_destroy (&p->mutex);
  77 + if (err) {
  78 + logerr (p, err, "%s(%s): pthread_mutex_destroy failed", cap, AUDIO_FUNC);
  79 + ret = -1;
  80 + }
  81 + return ret;
  82 +}
  83 +
  84 +int audio_pt_lock (struct audio_pt *p, const char *cap)
  85 +{
  86 + int err;
  87 +
  88 + err = pthread_mutex_lock (&p->mutex);
  89 + if (err) {
  90 + logerr (p, err, "%s(%s): pthread_mutex_lock failed", cap, AUDIO_FUNC);
  91 + return -1;
  92 + }
  93 + return 0;
  94 +}
  95 +
  96 +int audio_pt_unlock (struct audio_pt *p, const char *cap)
  97 +{
  98 + int err;
  99 +
  100 + err = pthread_mutex_unlock (&p->mutex);
  101 + if (err) {
  102 + logerr (p, err, "%s(%s): pthread_mutex_unlock failed", cap, AUDIO_FUNC);
  103 + return -1;
  104 + }
  105 + return 0;
  106 +}
  107 +
  108 +int audio_pt_wait (struct audio_pt *p, const char *cap)
  109 +{
  110 + int err;
  111 +
  112 + err = pthread_cond_wait (&p->cond, &p->mutex);
  113 + if (err) {
  114 + logerr (p, err, "%s(%s): pthread_cond_wait failed", cap, AUDIO_FUNC);
  115 + return -1;
  116 + }
  117 + return 0;
  118 +}
  119 +
  120 +int audio_pt_unlock_and_signal (struct audio_pt *p, const char *cap)
  121 +{
  122 + int err;
  123 +
  124 + err = pthread_mutex_unlock (&p->mutex);
  125 + if (err) {
  126 + logerr (p, err, "%s(%s): pthread_mutex_unlock failed", cap, AUDIO_FUNC);
  127 + return -1;
  128 + }
  129 + err = pthread_cond_signal (&p->cond);
  130 + if (err) {
  131 + logerr (p, err, "%s(%s): pthread_cond_signal failed", cap, AUDIO_FUNC);
  132 + return -1;
  133 + }
  134 + return 0;
  135 +}
  136 +
  137 +int audio_pt_join (struct audio_pt *p, void **arg, const char *cap)
  138 +{
  139 + int err;
  140 + void *ret;
  141 +
  142 + err = pthread_join (p->thread, &ret);
  143 + if (err) {
  144 + logerr (p, err, "%s(%s): pthread_join failed", cap, AUDIO_FUNC);
  145 + return -1;
  146 + }
  147 + *arg = ret;
  148 + return 0;
  149 +}
... ...
audio/audio_pt_int.h 0 โ†’ 100644
  1 +#ifndef QEMU_AUDIO_PT_INT_H
  2 +#define QEMU_AUDIO_PT_INT_H
  3 +
  4 +#include <pthread.h>
  5 +
  6 +struct audio_pt {
  7 + const char *drv;
  8 + pthread_t thread;
  9 + pthread_cond_t cond;
  10 + pthread_mutex_t mutex;
  11 +};
  12 +
  13 +int audio_pt_init (struct audio_pt *, void *(*) (void *), void *,
  14 + const char *, const char *);
  15 +int audio_pt_fini (struct audio_pt *, const char *);
  16 +int audio_pt_lock (struct audio_pt *, const char *);
  17 +int audio_pt_unlock (struct audio_pt *, const char *);
  18 +int audio_pt_wait (struct audio_pt *, const char *);
  19 +int audio_pt_unlock_and_signal (struct audio_pt *, const char *);
  20 +int audio_pt_join (struct audio_pt *, void **, const char *);
  21 +
  22 +#endif /* audio_pt_int.h */
... ...
audio/dsound_template.h
... ... @@ -23,16 +23,20 @@
23 23 */
24 24 #ifdef DSBTYPE_IN
25 25 #define NAME "capture buffer"
  26 +#define NAME2 "DirectSoundCapture"
26 27 #define TYPE in
27 28 #define IFACE IDirectSoundCaptureBuffer
28 29 #define BUFPTR LPDIRECTSOUNDCAPTUREBUFFER
29 30 #define FIELD dsound_capture_buffer
  31 +#define FIELD2 dsound_capture
30 32 #else
31 33 #define NAME "playback buffer"
  34 +#define NAME2 "DirectSound"
32 35 #define TYPE out
33 36 #define IFACE IDirectSoundBuffer
34 37 #define BUFPTR LPDIRECTSOUNDBUFFER
35 38 #define FIELD dsound_buffer
  39 +#define FIELD2 dsound
36 40 #endif
37 41  
38 42 static int glue (dsound_unlock_, TYPE) (
... ... @@ -192,6 +196,11 @@ static int dsound_init_out (HWVoiceOut *hw, audsettings_t *as)
192 196 DSBCAPS bc;
193 197 #endif
194 198  
  199 + if (!s->FIELD2) {
  200 + dsound_logerr ("Attempt to initialize voice without " NAME2 " object");
  201 + return -1;
  202 + }
  203 +
195 204 err = waveformat_from_audio_settings (&wfx, as);
196 205 if (err) {
197 206 return -1;
... ...
audio/dsoundaudio.c
... ... @@ -320,23 +320,22 @@ static int waveformat_from_audio_settings (WAVEFORMATEX *wfx, audsettings_t *as)
320 320  
321 321 switch (as->fmt) {
322 322 case AUD_FMT_S8:
323   - wfx->wBitsPerSample = 8;
324   - break;
325   -
326 323 case AUD_FMT_U8:
327 324 wfx->wBitsPerSample = 8;
328 325 break;
329 326  
330 327 case AUD_FMT_S16:
  328 + case AUD_FMT_U16:
331 329 wfx->wBitsPerSample = 16;
332 330 wfx->nAvgBytesPerSec <<= 1;
333 331 wfx->nBlockAlign <<= 1;
334 332 break;
335 333  
336   - case AUD_FMT_U16:
337   - wfx->wBitsPerSample = 16;
338   - wfx->nAvgBytesPerSec <<= 1;
339   - wfx->nBlockAlign <<= 1;
  334 + case AUD_FMT_S32:
  335 + case AUD_FMT_U32:
  336 + wfx->wBitsPerSample = 32;
  337 + wfx->nAvgBytesPerSec <<= 2;
  338 + wfx->nBlockAlign <<= 2;
340 339 break;
341 340  
342 341 default:
... ... @@ -387,8 +386,13 @@ static int waveformat_to_audio_settings (WAVEFORMATEX *wfx, audsettings_t *as)
387 386 as->fmt = AUD_FMT_S16;
388 387 break;
389 388  
  389 + case 32:
  390 + as->fmt = AUD_FMT_S32;
  391 + break;
  392 +
390 393 default:
391   - dolog ("Invalid wave format, bits per sample is not 8 or 16, but %d\n",
  394 + dolog ("Invalid wave format, bits per sample is not "
  395 + "8, 16 or 32, but %d\n",
392 396 wfx->wBitsPerSample);
393 397 return -1;
394 398 }
... ...
audio/esdaudio.c 0 โ†’ 100644
  1 +/*
  2 + * QEMU ESD audio driver
  3 + *
  4 + * Copyright (c) 2006 Frederick Reeve (brushed up by malc)
  5 + *
  6 + * Permission is hereby granted, free of charge, to any person obtaining a copy
  7 + * of this software and associated documentation files (the "Software"), to deal
  8 + * in the Software without restriction, including without limitation the rights
  9 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 + * copies of the Software, and to permit persons to whom the Software is
  11 + * furnished to do so, subject to the following conditions:
  12 + *
  13 + * The above copyright notice and this permission notice shall be included in
  14 + * all copies or substantial portions of the Software.
  15 + *
  16 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 + * THE SOFTWARE.
  23 + */
  24 +#include <esd.h>
  25 +#include "qemu-common.h"
  26 +#include "audio.h"
  27 +#include <signal.h>
  28 +
  29 +#define AUDIO_CAP "esd"
  30 +#include "audio_int.h"
  31 +#include "audio_pt_int.h"
  32 +
  33 +typedef struct {
  34 + HWVoiceOut hw;
  35 + int done;
  36 + int live;
  37 + int decr;
  38 + int rpos;
  39 + void *pcm_buf;
  40 + int fd;
  41 + struct audio_pt pt;
  42 +} ESDVoiceOut;
  43 +
  44 +typedef struct {
  45 + HWVoiceIn hw;
  46 + int done;
  47 + int dead;
  48 + int incr;
  49 + int wpos;
  50 + void *pcm_buf;
  51 + int fd;
  52 + struct audio_pt pt;
  53 +} ESDVoiceIn;
  54 +
  55 +static struct {
  56 + int samples;
  57 + int divisor;
  58 + char *dac_host;
  59 + char *adc_host;
  60 +} conf = {
  61 + 1024,
  62 + 2,
  63 + NULL,
  64 + NULL
  65 +};
  66 +
  67 +static void GCC_FMT_ATTR (2, 3) qesd_logerr (int err, const char *fmt, ...)
  68 +{
  69 + va_list ap;
  70 +
  71 + va_start (ap, fmt);
  72 + AUD_vlog (AUDIO_CAP, fmt, ap);
  73 + va_end (ap);
  74 +
  75 + AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
  76 +}
  77 +
  78 +/* playback */
  79 +static void *qesd_thread_out (void *arg)
  80 +{
  81 + ESDVoiceOut *esd = arg;
  82 + HWVoiceOut *hw = &esd->hw;
  83 + int threshold;
  84 +
  85 + threshold = conf.divisor ? hw->samples / conf.divisor : 0;
  86 +
  87 + for (;;) {
  88 + int decr, to_mix, rpos;
  89 +
  90 + for (;;) {
  91 + if (esd->done) {
  92 + goto exit;
  93 + }
  94 +
  95 + if (esd->live > threshold) {
  96 + break;
  97 + }
  98 +
  99 + if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) {
  100 + goto exit;
  101 + }
  102 + }
  103 +
  104 + decr = to_mix = esd->live;
  105 + rpos = hw->rpos;
  106 +
  107 + if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) {
  108 + return NULL;
  109 + }
  110 +
  111 + while (to_mix) {
  112 + ssize_t written;
  113 + int chunk = audio_MIN (to_mix, hw->samples - rpos);
  114 + st_sample_t *src = hw->mix_buf + rpos;
  115 +
  116 + hw->clip (esd->pcm_buf, src, chunk);
  117 +
  118 + again:
  119 + written = write (esd->fd, esd->pcm_buf, chunk << hw->info.shift);
  120 + if (written == -1) {
  121 + if (errno == EINTR || errno == EAGAIN) {
  122 + goto again;
  123 + }
  124 + qesd_logerr (errno, "write failed\n");
  125 + return NULL;
  126 + }
  127 +
  128 + if (written != chunk << hw->info.shift) {
  129 + int wsamples = written >> hw->info.shift;
  130 + int wbytes = wsamples << hw->info.shift;
  131 + if (wbytes != written) {
  132 + dolog ("warning: Misaligned write %d (requested %d), "
  133 + "alignment %d\n",
  134 + wbytes, written, hw->info.align + 1);
  135 + }
  136 + to_mix -= wsamples;
  137 + rpos = (rpos + wsamples) % hw->samples;
  138 + break;
  139 + }
  140 +
  141 + rpos = (rpos + chunk) % hw->samples;
  142 + to_mix -= chunk;
  143 + }
  144 +
  145 + if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
  146 + return NULL;
  147 + }
  148 +
  149 + esd->rpos = rpos;
  150 + esd->live -= decr;
  151 + esd->decr += decr;
  152 + }
  153 +
  154 + exit:
  155 + audio_pt_unlock (&esd->pt, AUDIO_FUNC);
  156 + return NULL;
  157 +}
  158 +
  159 +static int qesd_run_out (HWVoiceOut *hw)
  160 +{
  161 + int live, decr;
  162 + ESDVoiceOut *esd = (ESDVoiceOut *) hw;
  163 +
  164 + if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
  165 + return 0;
  166 + }
  167 +
  168 + live = audio_pcm_hw_get_live_out (hw);
  169 + decr = audio_MIN (live, esd->decr);
  170 + esd->decr -= decr;
  171 + esd->live = live - decr;
  172 + hw->rpos = esd->rpos;
  173 + if (esd->live > 0) {
  174 + audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
  175 + }
  176 + else {
  177 + audio_pt_unlock (&esd->pt, AUDIO_FUNC);
  178 + }
  179 + return decr;
  180 +}
  181 +
  182 +static int qesd_write (SWVoiceOut *sw, void *buf, int len)
  183 +{
  184 + return audio_pcm_sw_write (sw, buf, len);
  185 +}
  186 +
  187 +static int qesd_init_out (HWVoiceOut *hw, audsettings_t *as)
  188 +{
  189 + ESDVoiceOut *esd = (ESDVoiceOut *) hw;
  190 + audsettings_t obt_as = *as;
  191 + int esdfmt = ESD_STREAM | ESD_PLAY;
  192 + int err;
  193 + sigset_t set, old_set;
  194 +
  195 + sigfillset (&set);
  196 +
  197 + esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO;
  198 + switch (as->fmt) {
  199 + case AUD_FMT_S8:
  200 + case AUD_FMT_U8:
  201 + esdfmt |= ESD_BITS8;
  202 + obt_as.fmt = AUD_FMT_U8;
  203 + break;
  204 +
  205 + case AUD_FMT_S32:
  206 + case AUD_FMT_U32:
  207 + dolog ("Will use 16 instead of 32 bit samples\n");
  208 +
  209 + case AUD_FMT_S16:
  210 + case AUD_FMT_U16:
  211 + deffmt:
  212 + esdfmt |= ESD_BITS16;
  213 + obt_as.fmt = AUD_FMT_S16;
  214 + break;
  215 +
  216 + default:
  217 + dolog ("Internal logic error: Bad audio format %d\n", as->fmt);
  218 +#ifdef DEBUG_FMOD
  219 + abort ();
  220 +#endif
  221 + goto deffmt;
  222 +
  223 + }
  224 + obt_as.endianness = 0;
  225 +
  226 + audio_pcm_init_info (&hw->info, &obt_as);
  227 +
  228 + hw->samples = conf.samples;
  229 + esd->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
  230 + if (!esd->pcm_buf) {
  231 + dolog ("Could not allocate buffer (%d bytes)\n",
  232 + hw->samples << hw->info.shift);
  233 + return -1;
  234 + }
  235 +
  236 + esd->fd = -1;
  237 + err = pthread_sigmask (SIG_BLOCK, &set, &old_set);
  238 + if (err) {
  239 + qesd_logerr (err, "pthread_sigmask failed\n");
  240 + goto fail1;
  241 + }
  242 +
  243 + esd->fd = esd_play_stream (esdfmt, as->freq, conf.dac_host, NULL);
  244 + if (esd->fd < 0) {
  245 + qesd_logerr (errno, "esd_play_stream failed\n");
  246 + goto fail2;
  247 + }
  248 +
  249 + if (audio_pt_init (&esd->pt, qesd_thread_out, esd, AUDIO_CAP, AUDIO_FUNC)) {
  250 + goto fail3;
  251 + }
  252 +
  253 + err = pthread_sigmask (SIG_SETMASK, &old_set, NULL);
  254 + if (err) {
  255 + qesd_logerr (err, "pthread_sigmask(restore) failed\n");
  256 + }
  257 +
  258 + return 0;
  259 +
  260 + fail3:
  261 + if (close (esd->fd)) {
  262 + qesd_logerr (errno, "%s: close on esd socket(%d) failed\n",
  263 + AUDIO_FUNC, esd->fd);
  264 + }
  265 + esd->fd = -1;
  266 +
  267 + fail2:
  268 + err = pthread_sigmask (SIG_SETMASK, &old_set, NULL);
  269 + if (err) {
  270 + qesd_logerr (err, "pthread_sigmask(restore) failed\n");
  271 + }
  272 +
  273 + fail1:
  274 + qemu_free (esd->pcm_buf);
  275 + esd->pcm_buf = NULL;
  276 + return -1;
  277 +}
  278 +
  279 +static void qesd_fini_out (HWVoiceOut *hw)
  280 +{
  281 + void *ret;
  282 + ESDVoiceOut *esd = (ESDVoiceOut *) hw;
  283 +
  284 + audio_pt_lock (&esd->pt, AUDIO_FUNC);
  285 + esd->done = 1;
  286 + audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
  287 + audio_pt_join (&esd->pt, &ret, AUDIO_FUNC);
  288 +
  289 + if (esd->fd >= 0) {
  290 + if (close (esd->fd)) {
  291 + qesd_logerr (errno, "failed to close esd socket\n");
  292 + }
  293 + esd->fd = -1;
  294 + }
  295 +
  296 + audio_pt_fini (&esd->pt, AUDIO_FUNC);
  297 +
  298 + qemu_free (esd->pcm_buf);
  299 + esd->pcm_buf = NULL;
  300 +}
  301 +
  302 +static int qesd_ctl_out (HWVoiceOut *hw, int cmd, ...)
  303 +{
  304 + (void) hw;
  305 + (void) cmd;
  306 + return 0;
  307 +}
  308 +
  309 +/* capture */
  310 +static void *qesd_thread_in (void *arg)
  311 +{
  312 + ESDVoiceIn *esd = arg;
  313 + HWVoiceIn *hw = &esd->hw;
  314 + int threshold;
  315 +
  316 + threshold = conf.divisor ? hw->samples / conf.divisor : 0;
  317 +
  318 + for (;;) {
  319 + int incr, to_grab, wpos;
  320 +
  321 + for (;;) {
  322 + if (esd->done) {
  323 + goto exit;
  324 + }
  325 +
  326 + if (esd->dead > threshold) {
  327 + break;
  328 + }
  329 +
  330 + if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) {
  331 + goto exit;
  332 + }
  333 + }
  334 +
  335 + incr = to_grab = esd->dead;
  336 + wpos = hw->wpos;
  337 +
  338 + if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) {
  339 + return NULL;
  340 + }
  341 +
  342 + while (to_grab) {
  343 + ssize_t nread;
  344 + int chunk = audio_MIN (to_grab, hw->samples - wpos);
  345 + void *buf = advance (esd->pcm_buf, wpos);
  346 +
  347 + again:
  348 + nread = read (esd->fd, buf, chunk << hw->info.shift);
  349 + if (nread == -1) {
  350 + if (errno == EINTR || errno == EAGAIN) {
  351 + goto again;
  352 + }
  353 + qesd_logerr (errno, "read failed\n");
  354 + return NULL;
  355 + }
  356 +
  357 + if (nread != chunk << hw->info.shift) {
  358 + int rsamples = nread >> hw->info.shift;
  359 + int rbytes = rsamples << hw->info.shift;
  360 + if (rbytes != nread) {
  361 + dolog ("warning: Misaligned write %d (requested %d), "
  362 + "alignment %d\n",
  363 + rbytes, nread, hw->info.align + 1);
  364 + }
  365 + to_grab -= rsamples;
  366 + wpos = (wpos + rsamples) % hw->samples;
  367 + break;
  368 + }
  369 +
  370 + hw->conv (hw->conv_buf + wpos, buf, nread >> hw->info.shift,
  371 + &nominal_volume);
  372 + wpos = (wpos + chunk) % hw->samples;
  373 + to_grab -= chunk;
  374 + }
  375 +
  376 + if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
  377 + return NULL;
  378 + }
  379 +
  380 + esd->wpos = wpos;
  381 + esd->dead -= incr;
  382 + esd->incr += incr;
  383 + }
  384 +
  385 + exit:
  386 + audio_pt_unlock (&esd->pt, AUDIO_FUNC);
  387 + return NULL;
  388 +}
  389 +
  390 +static int qesd_run_in (HWVoiceIn *hw)
  391 +{
  392 + int live, incr, dead;
  393 + ESDVoiceIn *esd = (ESDVoiceIn *) hw;
  394 +
  395 + if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
  396 + return 0;
  397 + }
  398 +
  399 + live = audio_pcm_hw_get_live_in (hw);
  400 + dead = hw->samples - live;
  401 + incr = audio_MIN (dead, esd->incr);
  402 + esd->incr -= incr;
  403 + esd->dead = dead - incr;
  404 + hw->wpos = esd->wpos;
  405 + if (esd->dead > 0) {
  406 + audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
  407 + }
  408 + else {
  409 + audio_pt_unlock (&esd->pt, AUDIO_FUNC);
  410 + }
  411 + return incr;
  412 +}
  413 +
  414 +static int qesd_read (SWVoiceIn *sw, void *buf, int len)
  415 +{
  416 + return audio_pcm_sw_read (sw, buf, len);
  417 +}
  418 +
  419 +static int qesd_init_in (HWVoiceIn *hw, audsettings_t *as)
  420 +{
  421 + ESDVoiceIn *esd = (ESDVoiceIn *) hw;
  422 + audsettings_t obt_as = *as;
  423 + int esdfmt = ESD_STREAM | ESD_RECORD;
  424 + int err;
  425 + sigset_t set, old_set;
  426 +
  427 + sigfillset (&set);
  428 +
  429 + esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO;
  430 + switch (as->fmt) {
  431 + case AUD_FMT_S8:
  432 + case AUD_FMT_U8:
  433 + esdfmt |= ESD_BITS8;
  434 + obt_as.fmt = AUD_FMT_U8;
  435 + break;
  436 +
  437 + case AUD_FMT_S16:
  438 + case AUD_FMT_U16:
  439 + esdfmt |= ESD_BITS16;
  440 + obt_as.fmt = AUD_FMT_S16;
  441 + break;
  442 +
  443 + case AUD_FMT_S32:
  444 + case AUD_FMT_U32:
  445 + dolog ("Will use 16 instead of 32 bit samples\n");
  446 + esdfmt |= ESD_BITS16;
  447 + obt_as.fmt = AUD_FMT_S16;
  448 + break;
  449 + }
  450 + obt_as.endianness = 0;
  451 +
  452 + audio_pcm_init_info (&hw->info, &obt_as);
  453 +
  454 + hw->samples = conf.samples;
  455 + esd->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
  456 + if (!esd->pcm_buf) {
  457 + dolog ("Could not allocate buffer (%d bytes)\n",
  458 + hw->samples << hw->info.shift);
  459 + return -1;
  460 + }
  461 +
  462 + esd->fd = -1;
  463 +
  464 + err = pthread_sigmask (SIG_BLOCK, &set, &old_set);
  465 + if (err) {
  466 + qesd_logerr (err, "pthread_sigmask failed\n");
  467 + goto fail1;
  468 + }
  469 +
  470 + esd->fd = esd_record_stream (esdfmt, as->freq, conf.adc_host, NULL);
  471 + if (esd->fd < 0) {
  472 + qesd_logerr (errno, "esd_record_stream failed\n");
  473 + goto fail2;
  474 + }
  475 +
  476 + if (audio_pt_init (&esd->pt, qesd_thread_in, esd, AUDIO_CAP, AUDIO_FUNC)) {
  477 + goto fail3;
  478 + }
  479 +
  480 + err = pthread_sigmask (SIG_SETMASK, &old_set, NULL);
  481 + if (err) {
  482 + qesd_logerr (err, "pthread_sigmask(restore) failed\n");
  483 + }
  484 +
  485 + return 0;
  486 +
  487 + fail3:
  488 + if (close (esd->fd)) {
  489 + qesd_logerr (errno, "%s: close on esd socket(%d) failed\n",
  490 + AUDIO_FUNC, esd->fd);
  491 + }
  492 + esd->fd = -1;
  493 +
  494 + fail2:
  495 + err = pthread_sigmask (SIG_SETMASK, &old_set, NULL);
  496 + if (err) {
  497 + qesd_logerr (err, "pthread_sigmask(restore) failed\n");
  498 + }
  499 +
  500 + fail1:
  501 + qemu_free (esd->pcm_buf);
  502 + esd->pcm_buf = NULL;
  503 + return -1;
  504 +}
  505 +
  506 +static void qesd_fini_in (HWVoiceIn *hw)
  507 +{
  508 + void *ret;
  509 + ESDVoiceIn *esd = (ESDVoiceIn *) hw;
  510 +
  511 + audio_pt_lock (&esd->pt, AUDIO_FUNC);
  512 + esd->done = 1;
  513 + audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
  514 + audio_pt_join (&esd->pt, &ret, AUDIO_FUNC);
  515 +
  516 + if (esd->fd >= 0) {
  517 + if (close (esd->fd)) {
  518 + qesd_logerr (errno, "failed to close esd socket\n");
  519 + }
  520 + esd->fd = -1;
  521 + }
  522 +
  523 + audio_pt_fini (&esd->pt, AUDIO_FUNC);
  524 +
  525 + qemu_free (esd->pcm_buf);
  526 + esd->pcm_buf = NULL;
  527 +}
  528 +
  529 +static int qesd_ctl_in (HWVoiceIn *hw, int cmd, ...)
  530 +{
  531 + (void) hw;
  532 + (void) cmd;
  533 + return 0;
  534 +}
  535 +
  536 +/* common */
  537 +static void *qesd_audio_init (void)
  538 +{
  539 + return &conf;
  540 +}
  541 +
  542 +static void qesd_audio_fini (void *opaque)
  543 +{
  544 + (void) opaque;
  545 + ldebug ("esd_fini");
  546 +}
  547 +
  548 +struct audio_option qesd_options[] = {
  549 + {"SAMPLES", AUD_OPT_INT, &conf.samples,
  550 + "buffer size in samples", NULL, 0},
  551 +
  552 + {"DIVISOR", AUD_OPT_INT, &conf.divisor,
  553 + "threshold divisor", NULL, 0},
  554 +
  555 + {"DAC_HOST", AUD_OPT_STR, &conf.dac_host,
  556 + "playback host", NULL, 0},
  557 +
  558 + {"ADC_HOST", AUD_OPT_STR, &conf.adc_host,
  559 + "capture host", NULL, 0},
  560 +
  561 + {NULL, 0, NULL, NULL, NULL, 0}
  562 +};
  563 +
  564 +struct audio_pcm_ops qesd_pcm_ops = {
  565 + qesd_init_out,
  566 + qesd_fini_out,
  567 + qesd_run_out,
  568 + qesd_write,
  569 + qesd_ctl_out,
  570 +
  571 + qesd_init_in,
  572 + qesd_fini_in,
  573 + qesd_run_in,
  574 + qesd_read,
  575 + qesd_ctl_in,
  576 +};
  577 +
  578 +struct audio_driver esd_audio_driver = {
  579 + INIT_FIELD (name = ) "esd",
  580 + INIT_FIELD (descr = )
  581 + "http://en.wikipedia.org/wiki/Esound",
  582 + INIT_FIELD (options = ) qesd_options,
  583 + INIT_FIELD (init = ) qesd_audio_init,
  584 + INIT_FIELD (fini = ) qesd_audio_fini,
  585 + INIT_FIELD (pcm_ops = ) &qesd_pcm_ops,
  586 + INIT_FIELD (can_be_default = ) 0,
  587 + INIT_FIELD (max_voices_out = ) INT_MAX,
  588 + INIT_FIELD (max_voices_in = ) INT_MAX,
  589 + INIT_FIELD (voice_size_out = ) sizeof (ESDVoiceOut),
  590 + INIT_FIELD (voice_size_in = ) sizeof (ESDVoiceIn)
  591 +};
... ...
audio/ossaudio.c
... ... @@ -150,7 +150,7 @@ static int oss_to_audfmt (int ossfmt, audfmt_e *fmt, int *endianness)
150 150 {
151 151 switch (ossfmt) {
152 152 case AFMT_S8:
153   - *endianness =0;
  153 + *endianness = 0;
154 154 *fmt = AUD_FMT_S8;
155 155 break;
156 156  
... ...
audio/wavaudio.c
... ... @@ -44,7 +44,7 @@ static struct {
44 44 44100,
45 45 2,
46 46 AUD_FMT_S16,
47   - AUDIO_HOST_ENDIANNESS
  47 + 0
48 48 },
49 49 "qemu.wav"
50 50 };
... ...
configure
... ... @@ -89,6 +89,7 @@ oss=&quot;no&quot;
89 89 dsound="no"
90 90 coreaudio="no"
91 91 alsa="no"
  92 +esd="no"
92 93 fmod="no"
93 94 fmod_lib=""
94 95 fmod_inc=""
... ... @@ -261,6 +262,8 @@ for opt do
261 262 ;;
262 263 --enable-alsa) alsa="yes"
263 264 ;;
  265 + --enable-esd) esd="yes"
  266 + ;;
264 267 --enable-dsound) dsound="yes"
265 268 ;;
266 269 --enable-fmod) fmod="yes"
... ... @@ -405,6 +408,7 @@ echo &quot; --enable-mingw32 enable Win32 cross compilation with mingw32&quot;
405 408 echo " --enable-adlib enable Adlib emulation"
406 409 echo " --enable-coreaudio enable Coreaudio audio driver"
407 410 echo " --enable-alsa enable ALSA audio driver"
  411 +echo " --enable-esd enable EsoundD audio driver"
408 412 echo " --enable-fmod enable FMOD audio driver"
409 413 echo " --enable-dsound enable DirectSound audio driver"
410 414 echo " --disable-vnc-tls disable TLS encryption for VNC server"
... ... @@ -717,6 +721,7 @@ echo &quot;mingw32 support $mingw32&quot;
717 721 echo "Adlib support $adlib"
718 722 echo "CoreAudio support $coreaudio"
719 723 echo "ALSA support $alsa"
  724 +echo "EsounD support $esd"
720 725 echo "DSound support $dsound"
721 726 if test "$fmod" = "yes"; then
722 727 if test -z $fmod_lib || test -z $fmod_inc; then
... ... @@ -902,6 +907,10 @@ if test &quot;$alsa&quot; = &quot;yes&quot; ; then
902 907 echo "CONFIG_ALSA=yes" >> $config_mak
903 908 echo "#define CONFIG_ALSA 1" >> $config_h
904 909 fi
  910 +if test "$esd" = "yes" ; then
  911 + echo "CONFIG_ESD=yes" >> $config_mak
  912 + echo "#define CONFIG_ESD 1" >> $config_h
  913 +fi
905 914 if test "$dsound" = "yes" ; then
906 915 echo "CONFIG_DSOUND=yes" >> $config_mak
907 916 echo "#define CONFIG_DSOUND 1" >> $config_h
... ...
hw/dma.c
... ... @@ -439,6 +439,13 @@ static void dma_reset(void *opaque)
439 439 write_cont (d, (0x0d << d->dshift), 0);
440 440 }
441 441  
  442 +static int dma_phony_handler (void *opaque, int nchan, int dma_pos, int dma_len)
  443 +{
  444 + dolog ("unregistered DMA channel used nchan=%d dma_pos=%d dma_len=%d\n",
  445 + nchan, dma_pos, dma_len);
  446 + return dma_pos;
  447 +}
  448 +
442 449 /* dshift = 0: 8 bit DMA, 1 = 16 bit DMA */
443 450 static void dma_init2(struct dma_cont *d, int base, int dshift,
444 451 int page_base, int pageh_base)
... ... @@ -471,6 +478,9 @@ static void dma_init2(struct dma_cont *d, int base, int dshift,
471 478 }
472 479 qemu_register_reset(dma_reset, d);
473 480 dma_reset(d);
  481 + for (i = 0; i < LENOFA (d->regs); ++i) {
  482 + d->regs[i].transfer_handler = dma_phony_handler;
  483 + }
474 484 }
475 485  
476 486 static void dma_save (QEMUFile *f, void *opaque)
... ...
hw/sb16.c
... ... @@ -1193,6 +1193,12 @@ static int SB_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len)
1193 1193 SB16State *s = opaque;
1194 1194 int till, copy, written, free;
1195 1195  
  1196 + if (s->block_size <= 0) {
  1197 + dolog ("invalid block size=%d nchan=%d dma_pos=%d dma_len=%d\n",
  1198 + s->block_size, nchan, dma_pos, dma_len);
  1199 + return dma_pos;
  1200 + }
  1201 +
1196 1202 if (s->left_till_irq < 0) {
1197 1203 s->left_till_irq = s->block_size;
1198 1204 }
... ...