ac97: More complete S/PDIF output handling

This commit is contained in:
Jannik Vogel 2020-06-09 15:14:01 +02:00
parent 9464bad500
commit 1e7d8e43c0
2 changed files with 66 additions and 9 deletions

View File

@ -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

View File

@ -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;