From 2bc486612b6d7e51a5cd817d596af04a2bab80c4 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 20 Nov 2021 23:24:11 -0300 Subject: [PATCH] ES1371 improvements, including codec select --- src/include/86box/snd_ac97.h | 17 ++++++- src/sound/snd_ac97_codec.c | 88 ++++++++++++++++++++++++++++++------ src/sound/snd_audiopci.c | 54 ++++++++++++++++------ 3 files changed, 132 insertions(+), 27 deletions(-) diff --git a/src/include/86box/snd_ac97.h b/src/include/86box/snd_ac97.h index 7eb2d1cc5..9dff9a617 100644 --- a/src/include/86box/snd_ac97.h +++ b/src/include/86box/snd_ac97.h @@ -93,6 +93,18 @@ #define AC97_PRL (1 << 14) +/* New codecs should be added to the end of this enum to avoid breaking configs. */ +enum { + AC97_CODEC_AD1881 = 0, + AC97_CODEC_ALC100, + AC97_CODEC_CS4297, + AC97_CODEC_CS4297A, + AC97_CODEC_WM9701A, + AC97_CODEC_STAC9708, + AC97_CODEC_STAC9721 +}; + + typedef struct { const uint16_t index, value, write_mask; } ac97_vendor_reg_t; @@ -112,6 +124,7 @@ extern void ac97_codec_writew(ac97_codec_t *dev, uint8_t reg, uint16_t val); extern void ac97_codec_reset(void *priv); extern void ac97_codec_getattn(void *priv, uint8_t reg, int *l, int *r); extern uint32_t ac97_codec_getrate(void *priv, uint8_t reg); +extern const device_t *ac97_codec_get(int model); extern void ac97_via_set_slot(void *priv, int slot, int irq_pin); extern uint8_t ac97_via_read_status(void *priv, uint8_t modem); @@ -122,15 +135,17 @@ extern void ac97_via_remap_audio_codec(void *priv, uint16_t new_io_base, uint8_t extern void ac97_via_remap_modem_codec(void *priv, uint16_t new_io_base, uint8_t enable); -#ifdef EMU_DEVICE_H extern ac97_codec_t **ac97_codec, **ac97_modem_codec; extern int ac97_codec_count, ac97_modem_codec_count, ac97_codec_id, ac97_modem_codec_id; +#ifdef EMU_DEVICE_H extern const device_t ad1881_device; extern const device_t alc100_device; extern const device_t cs4297_device; extern const device_t cs4297a_device; +extern const device_t stac9708_device; +extern const device_t stac9721_device; extern const device_t wm9701a_device; extern const device_t ac97_via_device; diff --git a/src/sound/snd_ac97_codec.c b/src/sound/snd_ac97_codec.c index ac19cdd7b..f29a037a3 100644 --- a/src/sound/snd_ac97_codec.c +++ b/src/sound/snd_ac97_codec.c @@ -26,19 +26,12 @@ #include <86box/snd_ac97.h> -enum { - AC97_CODEC_AD1881, - AC97_CODEC_ALC100, - AC97_CODEC_CS4297, - AC97_CODEC_CS4297A, - AC97_CODEC_WM9701A -}; - static const struct { const uint32_t vendor_id, max_rate, misc_flags; /* definitions for misc_flags in snd_ac97.h */ const uint16_t reset_flags, extid_flags, /* definitions in snd_ac97.h */ powerdown_mask; /* bits [7:0] => register 26 bits [15:8]; bits [11:8] => register 2A bits [14:11] */ const ac97_vendor_reg_t *vendor_regs; /* bits [11:8] of index are the page number if applicable (registers [60:6F]) */ + const device_t *device; } ac97_codecs[] = { [AC97_CODEC_AD1881] = { .vendor_id = AC97_VENDOR_ID('A', 'D', 'S', 0x40), @@ -46,7 +39,8 @@ static const struct { .misc_flags = AC97_MASTER_6B | AC97_MONOOUT | AC97_PCBEEP | AC97_PHONE | AC97_VIDEO | AC97_AUXIN | AC97_POP | AC97_MS | AC97_LPBK, .reset_flags = (1 << AC97_3D_SHIFT), /* datasheet contradicts itself on AC97_HPOUT */ .extid_flags = AC97_VRA, - .powerdown_mask = 0x0bf + .powerdown_mask = 0x0bf, + .device = &ad1881_device }, [AC97_CODEC_ALC100] = { .vendor_id = AC97_VENDOR_ID('A', 'L', 'C', 0x20), @@ -54,7 +48,8 @@ static const struct { .misc_flags = AC97_AUXOUT | AC97_MONOOUT | AC97_PCBEEP | AC97_PHONE | AC97_VIDEO | AC97_AUXIN | AC97_POP | AC97_MS | AC97_LPBK, .reset_flags = (22 << AC97_3D_SHIFT), .extid_flags = AC97_AMAP, - .powerdown_mask = 0x0bf + .powerdown_mask = 0x0bf, + .device = &alc100_device }, [AC97_CODEC_CS4297] = { .vendor_id = AC97_VENDOR_ID('C', 'R', 'Y', 0x03), @@ -63,7 +58,8 @@ static const struct { .reset_flags = AC97_HPOUT | AC97_DAC_18B | AC97_ADC_18B, .extid_flags = 0, .powerdown_mask = 0x07f, - .vendor_regs = (const ac97_vendor_reg_t[]) {{0x05a, 0x0301, 0x0000}, {0}} + .vendor_regs = (const ac97_vendor_reg_t[]) {{0x5a, 0x0301, 0x0000}, {0}}, + .device = &cs4297_device }, [AC97_CODEC_CS4297A] = { .vendor_id = AC97_VENDOR_ID('C', 'R', 'Y', 0x11), @@ -72,7 +68,28 @@ static const struct { .reset_flags = AC97_HPOUT | AC97_DAC_20B | AC97_ADC_18B | (6 << AC97_3D_SHIFT), .extid_flags = AC97_AMAP, .powerdown_mask = 0x0ff, - .vendor_regs = (const ac97_vendor_reg_t[]) {{0x05e, 0x0000, 0x01b0}, {0x060, 0x0023, 0x0001}, {0x068, 0x0000, 0xdfff}, {0}} + .vendor_regs = (const ac97_vendor_reg_t[]) {{0x5e, 0x0000, 0x01b0}, {0x60, 0x0023, 0x0001}, {0x68, 0x0000, 0xdfff}, {0}}, + .device = &cs4297a_device + }, + [AC97_CODEC_STAC9708] = { + .vendor_id = AC97_VENDOR_ID(0x83, 0x84, 0x76, 0x08), + .max_rate = 48000, + .misc_flags = AC97_AUXOUT | AC97_MONOOUT | AC97_PCBEEP | AC97_PHONE | AC97_VIDEO | AC97_AUXIN | AC97_MS | AC97_LPBK, + .reset_flags = (26 << AC97_3D_SHIFT) | AC97_DAC_18B | AC97_ADC_18B, + .extid_flags = AC97_SDAC, + .powerdown_mask = 0x2ff, + .vendor_regs = (const ac97_vendor_reg_t []) {{0x6c, 0x0000, 0x0003}, {0x74, 0x0000, 0x0003}, {0}}, + .device = &stac9708_device + }, + [AC97_CODEC_STAC9721] = { + .vendor_id = AC97_VENDOR_ID(0x83, 0x84, 0x76, 0x09), + .max_rate = 48000, + .misc_flags = AC97_AUXOUT | AC97_MONOOUT | AC97_PCBEEP | AC97_PHONE | AC97_VIDEO | AC97_AUXIN | AC97_MS | AC97_LPBK, + .reset_flags = (26 << AC97_3D_SHIFT) | AC97_DAC_18B | AC97_ADC_18B, + .extid_flags = AC97_AMAP, + .powerdown_mask = 0x0ff, + .vendor_regs = (const ac97_vendor_reg_t []) {{0x6c, 0x0000, 0x0000}, {0x6e, 0x0000, 0x0003}, {0x70, 0x0000, 0xffff}, {0x72, 0x0000, 0x0006}, {0x74, 0x0000, 0x0003}, {0x76, 0x0000, 0xffff}, {0x78, 0x0000, 0x3802}, {0}}, + .device = &stac9721_device }, [AC97_CODEC_WM9701A] = { .vendor_id = AC97_VENDOR_ID('W', 'M', 'L', 0x00), @@ -80,7 +97,8 @@ static const struct { .misc_flags = AC97_AUXOUT | AC97_MONOOUT | AC97_PCBEEP | AC97_PHONE | AC97_VIDEO | AC97_AUXIN | AC97_MS | AC97_LPBK, .reset_flags = AC97_DAC_18B | AC97_ADC_18B, .extid_flags = 0, - .powerdown_mask = 0x03f + .powerdown_mask = 0x03f, + .device = &wm9701a_device } }; @@ -257,6 +275,13 @@ line_gain: val &= 0x9f1f; val &= 0x0003; break; + case 26: /* SigmaTel */ + i = 0x0003; + if (dev->extid_flags & AC97_SDAC) + i |= 0x000c; + val &= i; + break; + default: return; } @@ -433,6 +458,9 @@ ac97_codec_reset(void *priv) dev->regs[0x14 >> 1] = AC97_MUTE | 0x0808; if (dev->misc_flags & AC97_AUXIN) dev->regs[0x14 >> 1] = AC97_MUTE | 0x0808; + dev->regs[0x1c] = AC97_MUTE; /* record gain */ + if (dev->reset_flags & AC97_MICPCM) + dev->regs[0x1e] = AC97_MUTE; /* mic record gain */ if (dev->misc_flags & AC97_LDAC) dev->regs[0x36 >> 1] = AC97_MUTE_L; if (dev->misc_flags & AC97_CDAC) @@ -594,6 +622,16 @@ ac97_codec_close(void *priv) } +const device_t * +ac97_codec_get(int model) +{ + if ((model >= 0) && (model < (sizeof(ac97_codecs) / sizeof(ac97_codecs[0])))) + return ac97_codecs[model].device; + else + return &cs4297a_device; /* fallback */ +} + + const device_t ad1881_device = { "Analog Devices AD1881", @@ -642,6 +680,30 @@ const device_t cs4297a_device = NULL }; +const device_t stac9708_device = +{ + "SigmaTel STAC9708", + DEVICE_AC97, + AC97_CODEC_STAC9708, + ac97_codec_init, ac97_codec_close, ac97_codec_reset, + { NULL }, + NULL, + NULL, + NULL +}; + +const device_t stac9721_device = +{ + "SigmaTel STAC9721", + DEVICE_AC97, + AC97_CODEC_STAC9721, + ac97_codec_init, ac97_codec_close, ac97_codec_reset, + { NULL }, + NULL, + NULL, + NULL +}; + const device_t wm9701a_device = { "Wolfson WM9701A", diff --git a/src/sound/snd_audiopci.c b/src/sound/snd_audiopci.c index e93267376..22f8751a5 100644 --- a/src/sound/snd_audiopci.c +++ b/src/sound/snd_audiopci.c @@ -99,6 +99,7 @@ typedef struct { int64_t dac_latch, dac_time; int master_vol_l, master_vol_r, + pcm_vol_l, pcm_vol_r, cd_vol_l, cd_vol_r; int card; @@ -1019,6 +1020,7 @@ es1371_outl(uint16_t port, uint32_t val, void *p) ac97_codec_writew(dev->codec, val >> 16, val); ac97_codec_getattn(dev->codec, 0x02, &dev->master_vol_l, &dev->master_vol_r); + ac97_codec_getattn(dev->codec, 0x18, &dev->pcm_vol_l, &dev->pcm_vol_r); ac97_codec_getattn(dev->codec, 0x12, &dev->cd_vol_l, &dev->cd_vol_r); } break; @@ -1407,7 +1409,7 @@ es1371_pci_read(int func, int addr, void *p) case 0x06: return 0x10; /* Supports ACPI */ case 0x07: return 0x00; - case 0x08: return 0x02; /* Revision ID */ + case 0x08: return 0x08; /* Revision ID - 0x02 (datasheet, VMware) has issues with the 2001 Creative WDM driver */ case 0x09: return 0x00; /* Multimedia audio device */ case 0x0a: return 0x01; case 0x0b: return 0x04; @@ -1664,8 +1666,8 @@ es1371_update(es1371_t *dev) l >>= 1; r >>= 1; - l = (l * dev->master_vol_l) >> 15; - r = (r * dev->master_vol_r) >> 15; + l = (((l * dev->pcm_vol_l) >> 15) * dev->master_vol_l) >> 15; + r = (((r * dev->pcm_vol_r) >> 15) * dev->master_vol_r) >> 15; if (l < -32768) l = -32768; @@ -1694,7 +1696,7 @@ es1371_poll(void *p) es1371_update(dev); if (dev->int_ctrl & INT_UART_EN) { - audiopci_log("UART INT Enabled\n"); + //audiopci_log("UART INT Enabled\n"); if (dev->uart_ctrl & UART_CTRL_RXINTEN) { /* We currently don't implement MIDI Input. But if anything sets MIDI Input and Output together we'd have to take account @@ -1710,7 +1712,7 @@ es1371_poll(void *p) dev->uart_status |= (UART_STATUS_TXINT | UART_STATUS_TXRDY); } - audiopci_log("UART control = %02x\n", dev->uart_ctrl & (UART_CTRL_RXINTEN | UART_CTRL_TXINTEN)); + //audiopci_log("UART control = %02x\n", dev->uart_ctrl & (UART_CTRL_RXINTEN | UART_CTRL_TXINTEN)); es1371_update_irqs(dev); } @@ -1785,14 +1787,12 @@ static void es1371_filter_cd_audio(int channel, double *buffer, void *p) { es1371_t *dev = (es1371_t *)p; - int32_t c; + double c; int cd = channel ? dev->cd_vol_r : dev->cd_vol_l; int master = channel ? dev->master_vol_r : dev->master_vol_l; - c = (((int32_t) *buffer) * cd) >> 15; - c = (c * master) >> 15; - - *buffer = (double) c; + c = ((((*buffer) * cd) / 65536.0) * master) / 65536.0; + *buffer = c; } @@ -1858,7 +1858,7 @@ es1371_init(const device_t *info) ac97_codec_id = 0; /* Let the machine decide the codec on onboard implementations. */ if (!info->local) - device_add(&cs4297a_device); + device_add(ac97_codec_get(device_get_config_int("codec"))); es1371_reset(dev); @@ -1884,6 +1884,34 @@ es1371_speed_changed(void *p) } +static const device_config_t es1371_config[] = +{ + { + .name = "codec", + .description = "CODEC", + .type = CONFIG_SELECTION, + .selection = { + { + .description = "Crystal CS4297", + .value = AC97_CODEC_CS4297 + }, { + .description = "Crystal CS4297A", + .value = AC97_CODEC_CS4297A + }, { + .description = "SigmaTel STAC9708", + .value = AC97_CODEC_STAC9708 + }, { + .description = "SigmaTel STAC9721", + .value = AC97_CODEC_STAC9721 + } + }, + .default_int = AC97_CODEC_CS4297A + }, { + "", "", -1 + } +}; + + const device_t es1371_device = { "Ensoniq AudioPCI (ES1371)", @@ -1891,11 +1919,11 @@ const device_t es1371_device = 0, es1371_init, es1371_close, - NULL, + es1371_reset, { NULL }, es1371_speed_changed, NULL, - NULL + es1371_config }; const device_t es1371_onboard_device =