From 8cf5e3d77f302504a2aa7716f79212f2b9a33aa4 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 29 Jul 2021 13:21:12 -0300 Subject: [PATCH] Update VIA AC97 codec write behavior to match hardware --- src/sound/snd_ac97_codec.c | 12 ++++++------ src/sound/snd_ac97_via.c | 29 +++++++++++++++-------------- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/sound/snd_ac97_codec.c b/src/sound/snd_ac97_codec.c index 2ae310465..9cd47ad90 100644 --- a/src/sound/snd_ac97_codec.c +++ b/src/sound/snd_ac97_codec.c @@ -25,17 +25,17 @@ #include <86box/io.h> #include <86box/snd_ac97.h> -#define AC97_CODEC_ID(f, s, t, dev) ((((f) & 0xff) << 24) | (((s) & 0xff) << 16) | (((t) & 0xff) << 8) | ((dev) & 0xff)) +#define AC97_VENDOR_ID(f, s, t, dev) ((((f) & 0xff) << 24) | (((s) & 0xff) << 16) | (((t) & 0xff) << 8) | ((dev) & 0xff)) enum { - AC97_CODEC_ALC100 = AC97_CODEC_ID('A', 'L', 'C', 0x20), - AC97_CODEC_CS4297 = AC97_CODEC_ID('C', 'R', 'Y', 0x03), - AC97_CODEC_CS4297A = AC97_CODEC_ID('C', 'R', 'Y', 0x13), - AC97_CODEC_WM9701A = AC97_CODEC_ID('W', 'M', 'L', 0x00) + AC97_CODEC_ALC100 = AC97_VENDOR_ID('A', 'L', 'C', 0x20), + AC97_CODEC_CS4297 = AC97_VENDOR_ID('C', 'R', 'Y', 0x03), + AC97_CODEC_CS4297A = AC97_VENDOR_ID('C', 'R', 'Y', 0x13), + AC97_CODEC_WM9701A = AC97_VENDOR_ID('W', 'M', 'L', 0x00) }; -#define ENABLE_AC97_CODEC_LOG 1 + #ifdef ENABLE_AC97_CODEC_LOG int ac97_codec_do_log = ENABLE_AC97_CODEC_LOG; diff --git a/src/sound/snd_ac97_via.c b/src/sound/snd_ac97_via.c index 262872e5e..9d46dfccd 100644 --- a/src/sound/snd_ac97_via.c +++ b/src/sound/snd_ac97_via.c @@ -371,15 +371,22 @@ ac97_via_sgd_write(uint16_t addr, uint8_t val, void *priv) i = !!(dev->sgd_regs[0x83] & 0x40); codec = dev->codec[modem][i]; - /* Read from or write to codec. */ + /* Keep value in register if this codec is not present. */ if (codec) { + /* Read from or write to codec. */ if (val & 0x80) { - val &= 0x7e; - dev->sgd_regs[0x80] = dev->codec_shadow[modem].regs_codec[i][val] = ac97_codec_read(codec, val); - val |= 1; - dev->sgd_regs[0x81] = dev->codec_shadow[modem].regs_codec[i][val] = ac97_codec_read(codec, val); - } else { - val &= 0x7e; + if (val & 1) { /* return 0x00 on unaligned reads */ + dev->sgd_regs[0x80] = dev->sgd_regs[0x81] = 0x00; + } else { + dev->sgd_regs[0x80] = dev->codec_shadow[modem].regs_codec[i][val] = ac97_codec_read(codec, val); + val |= 1; + dev->sgd_regs[0x81] = dev->codec_shadow[modem].regs_codec[i][val] = ac97_codec_read(codec, val); + } + + /* Flag data/status/index for this codec as valid. */ + if (val & 0x80) + dev->sgd_regs[0x83] |= 0x02 << (i << 1); + } else if (!(val & 1)) { /* do nothing on unaligned writes */ ac97_codec_write(codec, val, dev->codec_shadow[modem].regs_codec[i][val] = dev->sgd_regs[0x80]); val |= 1; ac97_codec_write(codec, val, dev->codec_shadow[modem].regs_codec[i][val] = dev->sgd_regs[0x81]); @@ -388,12 +395,6 @@ ac97_via_sgd_write(uint16_t addr, uint8_t val, void *priv) if (!modem && !i) ac97_via_update_codec(dev); } - - /* Flag data/status/index for this codec as valid. */ - dev->sgd_regs[0x83] |= 0x02 << (i * 2); - } else if (val & 0x80) { - /* Unknown behavior when reading from an absent codec. */ - dev->sgd_regs[0x80] = dev->sgd_regs[0x81] = 0xff; } break; @@ -402,7 +403,7 @@ ac97_via_sgd_write(uint16_t addr, uint8_t val, void *priv) #if 0 /* race condition with Linux accessing a register and clearing status bits on the same dword write */ val = (dev->sgd_regs[addr] & ~(val & 0x0a)) | (val & 0xc0); #else - val = dev->sgd_regs[addr] | 0x0a | (val & 0xc0); + val = dev->sgd_regs[addr] | (val & 0xc0); #endif break; }