diff --git a/hw/audio/ac97.c b/hw/audio/ac97.c index bfe1c2555e..c186d90c22 100644 --- a/hw/audio/ac97.c +++ b/hw/audio/ac97.c @@ -176,6 +176,7 @@ enum { #define GET_BM(index) (((index) >> 4) & 7) +static void so_callback (void *opaque, int free); static void po_callback (void *opaque, int free); static void pi_callback (void *opaque, int avail); static void mc_callback (void *opaque, int avail); @@ -272,6 +273,10 @@ static void voice_set_active (AC97LinkState *s, int bm_index, int on) AUD_set_active_in (s->voice_mc, on); break; + case SO_INDEX: + AUD_set_active_out (s->voice_so, on); + break; + default: AUD_log ("ac97", "invalid bm_index(%d) in voice_set_active\n", bm_index); break; @@ -366,6 +371,18 @@ static void open_voice (AC97LinkState *s, int index, int freq) &as ); break; + + case SO_INDEX: + s->voice_so = AUD_open_out ( + &s->card, + s->voice_so, + "ac97.so", + s, + so_callback, + &as + ); + break; + } } else { @@ -385,6 +402,11 @@ static void open_voice (AC97LinkState *s, int index, int freq) AUD_close_in (&s->card, s->voice_mc); s->voice_mc = NULL; break; + + case SO_INDEX: + AUD_close_out (&s->card, s->voice_so); + s->voice_so = NULL; + break; } } } @@ -400,6 +422,8 @@ static void reset_voices (AC97LinkState *s, uint8_t active[LAST_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]); + open_voice (s, SO_INDEX, freq); + AUD_set_active_out (s->voice_so, active[SO_INDEX]); freq = mixer_load (s, AC97_MIC_ADC_Rate); open_voice (s, MC_INDEX, freq); @@ -434,6 +458,12 @@ static void update_combined_volume_out (AC97LinkState *s) rvol = (rvol * prvol) / 255; AUD_set_volume_out (s->voice_po, mute, lvol, rvol); + + mute = 1; + lvol = 0; + rvol = 0; + + AUD_set_volume_out (s->voice_so, mute, lvol, rvol); } static void update_volume_in (AC97LinkState *s) @@ -596,6 +626,7 @@ static void nam_writew (void *opaque, uint32_t addr, uint32_t val) mixer_store (s, AC97_PCM_LR_ADC_Rate, 0xbb80); open_voice (s, PI_INDEX, 48000); open_voice (s, PO_INDEX, 48000); + open_voice (s, SO_INDEX, 48000); } if (!(val & EACS_VRM)) { mixer_store (s, AC97_MIC_ADC_Rate, 0xbb80); @@ -609,6 +640,7 @@ static void nam_writew (void *opaque, uint32_t addr, uint32_t val) mixer_store (s, index, val); dolog ("Set front DAC rate to %d\n", val); open_voice (s, PO_INDEX, val); + open_voice (s, SO_INDEX, val); } else { dolog ("Attempt to set front DAC rate to %d, " @@ -933,7 +965,7 @@ static void nabm_writel (void *opaque, uint32_t addr, uint32_t val) } } -static int write_audio (AC97LinkState *s, AC97BusMasterRegs *r, +static int write_audio (AC97LinkState *s, int index, AC97BusMasterRegs *r, int max, int *stop) { uint8_t tmpbuf[4096]; @@ -952,7 +984,14 @@ static int write_audio (AC97LinkState *s, AC97BusMasterRegs *r, int copied; to_copy = audio_MIN (temp, sizeof (tmpbuf)); dma_memory_read (s->as, addr, tmpbuf, to_copy); - copied = AUD_write (s->voice_po, tmpbuf, to_copy); + switch (index) { + case PO_INDEX: + copied = AUD_write (s->voice_po, tmpbuf, to_copy); + break; + case SO_INDEX: + copied = AUD_write (s->voice_so, tmpbuf, to_copy); + break; + } dolog ("write_audio max=%x to_copy=%x copied=%x\n", max, to_copy, copied); if (!copied) { @@ -978,7 +1017,7 @@ static int write_audio (AC97LinkState *s, AC97BusMasterRegs *r, return written; } -static void write_bup (AC97LinkState *s, int elapsed) +static void write_bup (AC97LinkState *s, int index, int elapsed) { dolog ("write_bup\n"); if (!(s->bup_flag & BUP_SET)) { @@ -998,7 +1037,15 @@ static void write_bup (AC97LinkState *s, int elapsed) while (elapsed) { int temp = audio_MIN (elapsed, sizeof (s->silence)); while (temp) { - int copied = AUD_write (s->voice_po, s->silence, temp); + int copied; + switch (index) { + case PO_INDEX: + copied = AUD_write (s->voice_po, s->silence, temp); + break; + case SO_INDEX: + copied = AUD_write (s->voice_so, s->silence, temp); + break; + } if (!copied) return; temp -= copied; @@ -1057,7 +1104,8 @@ static void transfer_audio (AC97LinkState *s, int index, int elapsed) if (r->cr & CR_RPBM) { switch (index) { case PO_INDEX: - write_bup (s, elapsed); + case SO_INDEX: + write_bup (s, index, elapsed); break; } } @@ -1089,7 +1137,8 @@ static void transfer_audio (AC97LinkState *s, int index, int elapsed) switch (index) { case PO_INDEX: - temp = write_audio (s, r, elapsed, &stop); + case SO_INDEX: + temp = write_audio (s, index, r, elapsed, &stop); elapsed -= temp; r->picb -= (temp >> 1); break; @@ -1142,6 +1191,11 @@ static void po_callback (void *opaque, int free) transfer_audio (opaque, PO_INDEX, free); } +static void so_callback (void *opaque, int free) +{ + transfer_audio (opaque, SO_INDEX, free); +} + static int ac97_post_load (void *opaque, int version_id) { uint8_t active[LAST_INDEX]; @@ -1158,6 +1212,7 @@ static int ac97_post_load (void *opaque, int version_id) active[PI_INDEX] = !!(s->bm_regs[PI_INDEX].cr & CR_RPBM); active[PO_INDEX] = !!(s->bm_regs[PO_INDEX].cr & CR_RPBM); active[MC_INDEX] = !!(s->bm_regs[MC_INDEX].cr & CR_RPBM); + active[SO_INDEX] = !!(s->bm_regs[SO_INDEX].cr & CR_RPBM); reset_voices (s, active); s->bup_flag = 0; @@ -1274,9 +1329,10 @@ 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_bm_regs (s, &s->bm_regs[PI_INDEX]); + reset_bm_regs (s, &s->bm_regs[PO_INDEX]); + reset_bm_regs (s, &s->bm_regs[MC_INDEX]); + reset_bm_regs (s, &s->bm_regs[SO_INDEX]); /* * Reset the mixer too. The Windows XP driver seems to rely on diff --git a/hw/audio/ac97_int.h b/hw/audio/ac97_int.h index 54c218e8d1..1d5f29f02d 100644 --- a/hw/audio/ac97_int.h +++ b/hw/audio/ac97_int.h @@ -64,6 +64,7 @@ typedef struct AC97LinkState { SWVoiceIn *voice_pi; SWVoiceOut *voice_po; SWVoiceIn *voice_mc; + SWVoiceOut *voice_so; int invalid_freq[LAST_INDEX]; uint8_t silence[128]; int bup_flag;