AC97 Codec: Rework with modem and proper multi-codec support

This commit is contained in:
RichardG867
2025-11-15 23:45:19 -03:00
parent 91c9cd4af2
commit 0a1464444a
3 changed files with 254 additions and 87 deletions

View File

@@ -8,9 +8,11 @@
*
* Definitions for AC'97 audio emulation.
*
*
*
* Authors: RichardG, <richardg867@gmail.com>
*
* Copyright 2021 RichardG.
* Copyright 2021-2025 RichardG.
*/
#ifndef SOUND_AC97_H
#define SOUND_AC97_H
@@ -19,23 +21,26 @@
/* Misc support bits (misc_flags). Most of these are not part of any
registers, but control enabling/disabling of registers and bits. */
#define AC97_MASTER_6B (1 << 0) /* register 02 bits [13,5] (ML5/MR5) */
#define AC97_AUXOUT (1 << 1) /* register 04 */
#define AC97_AUXOUT_6B (1 << 2) /* register 04 bits [13,5] (ML5/MR5) */
#define AC97_MONOOUT (1 << 3) /* register 06 */
#define AC97_MONOOUT_6B (1 << 4) /* register 06 bit 5 (MM5) */
#define AC97_PCBEEP (1 << 5) /* register 0A */
#define AC97_PCBEEP_GEN (1 << 6) /* register 0A bits [12:5] (F[7:0]) */
#define AC97_PHONE (1 << 9) /* register 0C */
#define AC97_VIDEO (1 << 10) /* register 14 */
#define AC97_AUXIN (1 << 11) /* register 16 */
#define AC97_AUDIO (1 << 0) /* audio codec */
#define AC97_MODEM (1 << 1) /* modem codec */
#define AC97_MASTER_6B (1 << 2) /* register 02 bits [13,5] (ML5/MR5) */
#define AC97_AUXOUT (1 << 3) /* register 04 */
#define AC97_AUXOUT_6B (1 << 4) /* register 04 bits [13,5] (ML5/MR5) */
#define AC97_MONOOUT (1 << 5) /* register 06 */
#define AC97_MONOOUT_6B (1 << 6) /* register 06 bit 5 (MM5) */
#define AC97_PCBEEP (1 << 9) /* register 0A */
#define AC97_PCBEEP_GEN (1 << 10) /* register 0A bits [12:5] (F[7:0]) */
#define AC97_PHONE (1 << 11) /* register 0C */
#define AC97_VIDEO (1 << 12) /* register 14 */
#define AC97_AUXIN (1 << 13) /* register 16 */
#define AC97_POP (1 << 15) /* register 20 bit 15 (POP) - definition shared with General Purpose bits */
#define AC97_MS (1 << 8) /* register 20 bit 8 (MS) - definition shared with General Purpose bits */
#define AC97_LPBK (1 << 7) /* register 20 bit 7 (LPBK) - definition shared with General Purpose bits */
#define AC97_DSA (1 << 12) /* register 28 bits [5:4] (DSA[1:0]) */
#define AC97_LFE_6B (1 << 13) /* register 36 bit 13 (LFE5) */
#define AC97_CENTER_6B (1 << 14) /* register 36 bit 5 (CNT5) */
#define AC97_SURR_6B (1 << 16) /* register 38 bits [13,5] (LSR5/RSR5) */
#define AC97_DSA (1 << 14) /* register 28 bits [5:4] (DSA[1:0]) */
#define AC97_LFE_6B (1 << 16) /* register 36 bit 13 (LFE5) */
#define AC97_CENTER_6B (1 << 17) /* register 36 bit 5 (CNT5) */
#define AC97_SURR_6B (1 << 18) /* register 38 bits [13,5] (LSR5/RSR5) */
#define AC97_GAIN_3B (1 << 19) /* registers [1C:1E] (audio) or [46:4A] (modem) bits [8,0] are always 0 (spec violation?) if this is set */
/* Reset bits (reset_flags), register 00. */
#define AC97_MICPCM (1 << 0)
@@ -89,6 +94,14 @@
#define AC97_PRK (1 << 13)
#define AC97_PRL (1 << 14)
/* Extended Modem ID bits, register 3C. */
#define AC97_LIN1 (1 << 0)
#define AC97_LIN2 (1 << 1)
#define AC97_HSET (1 << 2)
#define AC97_CID1 (1 << 3)
#define AC97_CID2 (1 << 4)
#define AC97_CIDR (1 << 7) /* special case: not part of register 3C, but rather 56 bit 13 */
/* Codec IDs. */
#define AC97_CODEC_AD1881 AC97_VENDOR_ID('A', 'D', 'S', 0x40)
#define AC97_CODEC_AK4540 AC97_VENDOR_ID('A', 'D', 'S', 0x40)
@@ -115,6 +128,8 @@ typedef struct ac97_codec_t {
uint8_t vendor_reg_page_max;
const ac97_vendor_reg_t *vendor_regs;
uint16_t *vendor_reg_pages;
uint16_t gpi;
uint16_t gpo;
} ac97_codec_t;
extern uint16_t ac97_codec_readw(ac97_codec_t *dev, uint8_t reg);
@@ -122,6 +137,8 @@ extern void ac97_codec_writew(ac97_codec_t *dev, uint8_t reg, uint16_
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 void ac97_codec_setgpi(void *priv, uint16_t gpi);
extern void ac97_codec_setgpo(void *priv, uint16_t gpo);
extern const device_t *ac97_codec_get(uint32_t id);
extern void ac97_via_set_slot(void *priv, int slot, int irq_pin);
@@ -133,11 +150,8 @@ extern void ac97_via_remap_audio_codec(void *priv, uint16_t new_io_base, uint
extern void ac97_via_remap_modem_codec(void *priv, uint16_t new_io_base, uint8_t enable);
extern ac97_codec_t **ac97_codec;
extern ac97_codec_t **ac97_modem_codec;
extern int ac97_codec_count;
extern int ac97_modem_codec_count;
extern int ac97_codec_id;
extern int ac97_modem_codec_id;
#ifdef EMU_DEVICE_H
extern const device_t ad1881_device;

View File

@@ -10,7 +10,7 @@
*
* Authors: RichardG, <richardg867@gmail.com>
*
* Copyright 2021 RichardG.
* Copyright 2021-2025 RichardG.
*/
#include <stdarg.h>
#include <stdint.h>
@@ -35,7 +35,10 @@ static const struct {
uint16_t reset_flags;
uint16_t extid_flags;
uint8_t pcsr_mask; /* register 26 bits [15:8] */
uint8_t eascr_mask; /* register 2A bits [14:11] */
uint8_t eascr_mask; /* register 2A bits [14:11] (audio) or 56 bits ... */
uint8_t modem_flags;
uint16_t gpi_mask; /* modem GPIO input-capable bits */
uint16_t gpo_mask; /* modem GPIO output-capable bits */
const ac97_vendor_reg_t *vendor_regs;
} ac97_codecs[] = {
@@ -44,7 +47,7 @@ static const struct {
.device = &ad1881_device,
.min_rate = 7000,
.max_rate = 48000,
.misc_flags = AC97_MASTER_6B | AC97_MONOOUT | AC97_PCBEEP | AC97_PHONE | AC97_VIDEO | AC97_AUXIN | AC97_POP | AC97_MS | AC97_LPBK,
.misc_flags = AC97_AUDIO | 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,
.pcsr_mask = 0xbf,
@@ -52,26 +55,26 @@ static const struct {
},
{
.device = &ak4540_device,
.misc_flags = AC97_MONOOUT | AC97_PCBEEP | AC97_PHONE | AC97_VIDEO | AC97_AUXIN | AC97_MS | AC97_LPBK,
.misc_flags = AC97_AUDIO | AC97_MONOOUT | AC97_PCBEEP | AC97_PHONE | AC97_VIDEO | AC97_AUXIN | AC97_MS | AC97_LPBK,
.pcsr_mask = 0x1f
},
{
.device = &alc100_device,
.misc_flags = AC97_AUXOUT | AC97_MONOOUT | AC97_PCBEEP | AC97_PHONE | AC97_VIDEO | AC97_AUXIN | AC97_POP | AC97_MS | AC97_LPBK,
.misc_flags = AC97_AUDIO | 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,
.pcsr_mask = 0xbf
},
{
.device = &cs4297_device,
.misc_flags = AC97_MASTER_6B | AC97_AUXOUT | AC97_AUXOUT_6B | AC97_MONOOUT | AC97_MONOOUT_6B | AC97_PCBEEP | AC97_PHONE | AC97_VIDEO | AC97_AUXIN | AC97_MS | AC97_LPBK,
.misc_flags = AC97_AUDIO | AC97_MASTER_6B | AC97_AUXOUT | AC97_AUXOUT_6B | AC97_MONOOUT | AC97_MONOOUT_6B | AC97_PCBEEP | AC97_PHONE | AC97_VIDEO | AC97_AUXIN | AC97_MS | AC97_LPBK,
.reset_flags = AC97_HPOUT | AC97_DAC_18B | AC97_ADC_18B,
.pcsr_mask = 0x7f,
.vendor_regs = (const ac97_vendor_reg_t[]) {{0, 0x5a, 0x0301, 0x0000}, {0}}
},
{
.device = &cs4297a_device,
.misc_flags = AC97_MASTER_6B | AC97_AUXOUT | AC97_MONOOUT | AC97_PCBEEP | AC97_PHONE | AC97_VIDEO | AC97_AUXIN | AC97_MS | AC97_LPBK,
.misc_flags = AC97_AUDIO | AC97_MASTER_6B | AC97_AUXOUT | AC97_MONOOUT | AC97_PCBEEP | AC97_PHONE | AC97_VIDEO | AC97_AUXIN | AC97_MS | AC97_LPBK,
.reset_flags = AC97_HPOUT | AC97_DAC_20B | AC97_ADC_18B | (6 << AC97_3D_SHIFT),
.extid_flags = AC97_AMAP,
.pcsr_mask = 0xff,
@@ -79,7 +82,7 @@ static const struct {
},
{
.device = &stac9708_device,
.misc_flags = AC97_AUXOUT | AC97_MONOOUT | AC97_PCBEEP | AC97_PHONE | AC97_VIDEO | AC97_AUXIN | AC97_MS | AC97_LPBK,
.misc_flags = AC97_AUDIO | 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,
.pcsr_mask = 0xff,
@@ -88,7 +91,7 @@ static const struct {
},
{
.device = &stac9721_device,
.misc_flags = AC97_AUXOUT | AC97_MONOOUT | AC97_PCBEEP | AC97_PHONE | AC97_VIDEO | AC97_AUXIN | AC97_MS | AC97_LPBK,
.misc_flags = AC97_AUDIO | 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,
.pcsr_mask = 0xff,
@@ -96,18 +99,18 @@ static const struct {
},
{
.device = &tr28023_device,
.misc_flags = AC97_MASTER_6B | AC97_MONOOUT | AC97_MONOOUT_6B | AC97_PCBEEP | AC97_PHONE | AC97_POP | AC97_MS | AC97_LPBK,
.misc_flags = AC97_AUDIO | AC97_MASTER_6B | AC97_MONOOUT | AC97_MONOOUT_6B | AC97_PCBEEP | AC97_PHONE | AC97_POP | AC97_MS | AC97_LPBK,
.pcsr_mask = 0x3f
},
{
.device = &w83971d_device,
.misc_flags = AC97_MASTER_6B | AC97_MONOOUT | AC97_MONOOUT_6B | AC97_PCBEEP | AC97_PHONE | AC97_VIDEO | AC97_AUXIN | AC97_MS | AC97_LPBK,
.misc_flags = AC97_AUDIO | AC97_MASTER_6B | AC97_MONOOUT | AC97_MONOOUT_6B | AC97_PCBEEP | AC97_PHONE | AC97_VIDEO | AC97_AUXIN | AC97_MS | AC97_LPBK,
.reset_flags = (27 << AC97_3D_SHIFT),
.pcsr_mask = 0x3f
},
{
.device = &wm9701a_device,
.misc_flags = AC97_AUXOUT | AC97_MONOOUT | AC97_PCBEEP | AC97_PHONE | AC97_VIDEO | AC97_AUXIN | AC97_MS | AC97_LPBK,
.misc_flags = AC97_AUDIO | AC97_AUXOUT | AC97_MONOOUT | AC97_PCBEEP | AC97_PHONE | AC97_VIDEO | AC97_AUXIN | AC97_MS | AC97_LPBK,
.reset_flags = AC97_DAC_18B | AC97_ADC_18B,
.pcsr_mask = 0x3f
}
@@ -143,11 +146,10 @@ static const int32_t codec_attn[] = {
};
ac97_codec_t **ac97_codec = NULL;
ac97_codec_t **ac97_modem_codec = NULL;
int ac97_codec_count = 0;
int ac97_modem_codec_count = 0;
int ac97_codec_id = 0;
int ac97_modem_codec_id = 0;
static void ac97_codec_reset_ex(ac97_codec_t *dev, uint8_t flags);
uint16_t
ac97_codec_readw(ac97_codec_t *dev, uint8_t reg)
@@ -155,10 +157,15 @@ ac97_codec_readw(ac97_codec_t *dev, uint8_t reg)
/* Redirect a read from extended pages 1+ to the right array. */
reg &= 0x7e;
uint16_t ret = dev->regs[0x24 >> 1] & 0x000f;
if ((ret > 0) && (reg >= 0x60) && (reg < 0x6f))
if ((ret > 0) && (reg >= 0x60) && (reg < 0x6f)) { /* Extended */
ret = (ret <= dev->vendor_reg_page_max) ? dev->vendor_reg_pages[(ret << 3) | ((reg & 0x0e) >> 1)] : 0;
else
} else if (reg == 0x54) { /* GPIO Status */
ret = dev->gpo & ~dev->regs[0x4c >> 1]; /* outputs */
ret |= dev->gpi & dev->regs[0x4c >> 1] & ~dev->regs[0x50 >> 1]; /* non-sticky inputs */
ret |= dev->regs[reg >> 1] & dev->regs[0x4c >> 1] & dev->regs[0x50 >> 1]; /* sticky inputs */
} else {
ret = dev->regs[reg >> 1];
}
ac97_codec_log("AC97 Codec %d: readw(%02X) = %04X\n", dev->codec_id, reg, ret);
@@ -175,9 +182,15 @@ ac97_codec_writew(ac97_codec_t *dev, uint8_t reg, uint16_t val)
uint16_t prev = dev->regs[reg >> 1];
int j;
/* Initial filtering by codec type. */
if (!(ac97_codecs[dev->model].misc_flags & AC97_AUDIO) && (reg <= 0x3a))
return;
if (!(ac97_codecs[dev->model].misc_flags & AC97_MODEM) && (reg >= 0x3c) && (reg <= 0x58))
return;
switch (reg) {
case 0x00: /* Reset / ID code */
ac97_codec_reset(dev);
ac97_codec_reset_ex(dev, AC97_AUDIO);
return;
case 0x02: /* Master Volume */
@@ -260,13 +273,13 @@ line_gain:
break;
case 0x1c: /* Record Gain */
val &= 0x8f0f;
val &= (ac97_codecs[dev->model].misc_flags & AC97_GAIN_3B) ? 0x8e0e : 0x8f0f;
break;
case 0x1e: /* Record Gain Mic */
if (!(ac97_codecs[dev->model].reset_flags & AC97_MICPCM))
return;
val &= 0x800f;
val &= (ac97_codecs[dev->model].misc_flags & AC97_GAIN_3B) ? 0x800e : 0x800f;
break;
case 0x20: /* General Purpose */
@@ -350,11 +363,11 @@ line_gain:
case 0x2c: /* PCM Front DAC Rate */
case 0x32: /* PCM L/R ADC Rate */
rate: /* Writable only if VRA/VRM is set. */
rate_vrx: /* Writable only if VRA/VRM is set. */
i = (reg >= 0x32) ? AC97_VRM : AC97_VRA;
if (!(ac97_codecs[dev->model].extid_flags & i))
return;
rate:
/* Limit to supported sample rate range. */
if (val < ac97_codecs[dev->model].min_rate)
val = ac97_codecs[dev->model].min_rate;
@@ -365,17 +378,17 @@ rate: /* Writable only if VRA/VRM is set. */
case 0x2e: /* PCM Surround DAC Rate */
if (!(ac97_codecs[dev->model].extid_flags & AC97_SDAC))
return;
goto rate;
goto rate_vrx;
case 0x30: /* PCM LFE DAC Rate */
if (!(ac97_codecs[dev->model].extid_flags & AC97_LDAC))
return;
goto rate;
goto rate_vrx;
case 0x34: /* Mic ADC Rate */
if (!(ac97_codecs[dev->model].reset_flags & AC97_MICPCM))
return;
goto rate;
goto rate_vrx;
case 0x36: /* Center/LFE Volume */
if (ac97_codecs[dev->model].extid_flags & AC97_LDAC)
@@ -406,6 +419,86 @@ rate: /* Writable only if VRA/VRM is set. */
return;
break;
case 0x3c: /* Reset / Extended Modem ID */
ac97_codec_reset_ex(dev, AC97_MODEM);
return;
case 0x3e: /* Extended Modem Control/Status */
i = 0x0300;
if (ac97_codecs[dev->model].modem_flags & AC97_LIN1)
i |= 0x0c00;
if (ac97_codecs[dev->model].modem_flags & AC97_LIN2)
i |= 0x3000;
if (ac97_codecs[dev->model].modem_flags & AC97_HSET)
i |= 0xc000;
val &= i;
/* Update status bits to reflect powerdowns. */
val |= (~val & i) >> 8;
break;
case 0x40: /* Line1 DAC/ADC Rate */
if (!(ac97_codecs[dev->model].modem_flags & AC97_LIN1))
return;
goto rate;
case 0x42: /* Line2 DAC/ADC Rate */
if (!(ac97_codecs[dev->model].modem_flags & AC97_LIN2))
return;
goto rate;
case 0x44: /* Handset DAC/ADC Rate */
if (!(ac97_codecs[dev->model].modem_flags & AC97_HSET))
return;
goto rate;
case 0x46: /* Line 1 DAC/ADC Level */
if (!(ac97_codecs[dev->model].modem_flags & AC97_LIN1))
return;
modem_gain:
val &= (ac97_codecs[dev->model].misc_flags & AC97_GAIN_3B) ? 0x8e8e : 0x8f8f;
break;
case 0x48: /* Line 2 DAC/ADC Level */
if (!(ac97_codecs[dev->model].modem_flags & AC97_LIN2))
return;
goto modem_gain;
case 0x4a: /* Handset DAC/ADC Level */
if (!(ac97_codecs[dev->model].modem_flags & AC97_HSET))
return;
goto modem_gain;
case 0x56: /* Miscellaneous Modem AFE Status/Control */
if (ac97_codecs[dev->model].modem_flags & AC97_LIN1)
i |= 0x0007;
if (ac97_codecs[dev->model].modem_flags & AC97_LIN2)
i |= 0x0070;
if (ac97_codecs[dev->model].modem_flags & AC97_HSET)
i |= 0x0700;
val &= i;
break;
case 0x4c: /* GPIO Pin Configuration */
val &= ac97_codecs[dev->model].gpi_mask | ac97_codecs[dev->model].gpo_mask;
break;
case 0x4e: /* GPIO Pin Polarity/Type */
val |= ~(ac97_codecs[dev->model].gpi_mask | ac97_codecs[dev->model].gpo_mask);
break;
case 0x50: /* GPIO Pin Sticky */
dev->regs[0x54 >> 1] &= val; /* clear sticky inputs that are no longer sticky (assumed undefined behavior) */
fallthrough;
case 0x52: /* GPIO Pin Wake-up Mask */
val &= ac97_codecs[dev->model].gpi_mask;
break;
case 0x54: /* GPIO Pin Status */
val = dev->regs[reg >> 1] & ~val; /* clear sticky inputs */
break;
case 0x60 ... 0x6e: /* Extended */
/* Get extended register page. */
i = dev->regs[0x24 >> 1] & 0x000f;
@@ -462,47 +555,83 @@ void
ac97_codec_reset(void *priv)
{
ac97_codec_t *dev = (ac97_codec_t *) priv;
uint16_t i;
ac97_codec_reset_ex(dev, AC97_AUDIO | AC97_MODEM);
}
ac97_codec_log("AC97 Codec %d: reset()\n", dev->codec_id);
static void
ac97_codec_reset_ex(ac97_codec_t *dev, uint8_t flags)
{
ac97_codec_log("AC97 Codec %d: reset(%02X)\n", dev->codec_id, flags);
memset(dev->regs, 0, sizeof(dev->regs));
/* Set default level and gain values. */
dev->regs[0x02 >> 1] = AC97_MUTE;
if (ac97_codecs[dev->model].misc_flags & AC97_AUXOUT)
dev->regs[0x04 >> 1] = AC97_MUTE;
if (ac97_codecs[dev->model].misc_flags & AC97_MONOOUT)
dev->regs[0x06 >> 1] = AC97_MUTE;
if (ac97_codecs[dev->model].misc_flags & AC97_PHONE)
dev->regs[0x0c >> 1] = AC97_MUTE | 0x0008;
dev->regs[0x0e >> 1] = AC97_MUTE | 0x0008; /* mic */
dev->regs[0x10 >> 1] = dev->regs[0x12 >> 1] = dev->regs[0x18 >> 1] = AC97_MUTE | 0x0808; /* line in, CD, PCM out */
if (ac97_codecs[dev->model].misc_flags & AC97_VIDEO)
dev->regs[0x14 >> 1] = AC97_MUTE | 0x0808;
if (ac97_codecs[dev->model].misc_flags & AC97_AUXIN)
dev->regs[0x14 >> 1] = AC97_MUTE | 0x0808;
dev->regs[0x1c >> 1] = AC97_MUTE; /* record gain */
if (ac97_codecs[dev->model].reset_flags & AC97_MICPCM)
dev->regs[0x1e >> 1] = AC97_MUTE; /* mic record gain */
if (ac97_codecs[dev->model].misc_flags & AC97_LDAC)
dev->regs[0x36 >> 1] = AC97_MUTE_L;
if (ac97_codecs[dev->model].misc_flags & AC97_CDAC)
dev->regs[0x36 >> 1] |= AC97_MUTE_R;
if (ac97_codecs[dev->model].misc_flags & AC97_SDAC)
dev->regs[0x38 >> 1] = AC97_MUTE_L | AC97_MUTE_R;
if ((flags & AC97_AUDIO) && (ac97_codecs[dev->model].misc_flags & AC97_AUDIO)) {
/* Set default level and gain values. */
dev->regs[0x02 >> 1] = AC97_MUTE;
if (ac97_codecs[dev->model].misc_flags & AC97_AUXOUT)
dev->regs[0x04 >> 1] = AC97_MUTE;
if (ac97_codecs[dev->model].misc_flags & AC97_MONOOUT)
dev->regs[0x06 >> 1] = AC97_MUTE;
if (ac97_codecs[dev->model].misc_flags & AC97_PHONE)
dev->regs[0x0c >> 1] = AC97_MUTE | 0x0008;
dev->regs[0x0e >> 1] = AC97_MUTE | 0x0008; /* mic */
dev->regs[0x10 >> 1] = dev->regs[0x12 >> 1] = dev->regs[0x18 >> 1] = AC97_MUTE | 0x0808; /* line in, CD, PCM out */
if (ac97_codecs[dev->model].misc_flags & AC97_VIDEO)
dev->regs[0x14 >> 1] = AC97_MUTE | 0x0808;
if (ac97_codecs[dev->model].misc_flags & AC97_AUXIN)
dev->regs[0x16 >> 1] = AC97_MUTE | 0x0808;
dev->regs[0x18 >> 1] = AC97_MUTE | 0x0808; /* PCM */
dev->regs[0x1c >> 1] = AC97_MUTE; /* record gain */
if (ac97_codecs[dev->model].reset_flags & AC97_MICPCM)
dev->regs[0x1e >> 1] = AC97_MUTE; /* mic record gain */
if (ac97_codecs[dev->model].misc_flags & AC97_LDAC)
dev->regs[0x36 >> 1] = AC97_MUTE_L;
if (ac97_codecs[dev->model].misc_flags & AC97_CDAC)
dev->regs[0x36 >> 1] |= AC97_MUTE_R;
if (ac97_codecs[dev->model].misc_flags & AC97_SDAC)
dev->regs[0x38 >> 1] = AC97_MUTE_L | AC97_MUTE_R;
/* Set flags. */
dev->regs[0x00 >> 1] = ac97_codecs[dev->model].reset_flags;
dev->regs[0x26 >> 1] = 0x000f; /* codec ready */
dev->regs[0x28 >> 1] = (dev->codec_id << 14) | ac97_codecs[dev->model].extid_flags;
ac97_codec_writew(dev, 0x2a, 0x0000); /* reset variable DAC/ADC sample rates */
i = ac97_codecs[dev->model].extid_flags & (AC97_CDAC | AC97_SDAC | AC97_LDAC);
dev->regs[0x2a >> 1] |= i | (i << 5); /* any additional DACs are ready but powered down */
if (ac97_codecs[dev->model].extid_flags & AC97_SPDIF)
dev->regs[0x2a >> 1] |= AC97_SPCV;
if (ac97_codecs[dev->model].reset_flags & AC97_MICPCM)
dev->regs[0x2a >> 1] |= AC97_MADC | AC97_PRL;
/* Set flags. */
dev->regs[0x00 >> 1] = ac97_codecs[dev->model].reset_flags;
dev->regs[0x26 >> 1] = 0x000f; /* codec ready */
dev->regs[0x28 >> 1] = (dev->codec_id << 14) | ac97_codecs[dev->model].extid_flags;
ac97_codec_writew(dev, 0x2a, 0x0000); /* reset variable DAC/ADC sample rates */
uint16_t i = ac97_codecs[dev->model].extid_flags & (AC97_CDAC | AC97_SDAC | AC97_LDAC);
dev->regs[0x2a >> 1] |= i | (i << 5); /* any additional DACs are ready but powered down */
if (ac97_codecs[dev->model].extid_flags & AC97_SPDIF)
dev->regs[0x2a >> 1] |= AC97_SPCV;
if (ac97_codecs[dev->model].reset_flags & AC97_MICPCM)
dev->regs[0x2a >> 1] |= AC97_MADC | AC97_PRL;
}
if ((flags & AC97_MODEM) && (ac97_codecs[dev->model].misc_flags & AC97_MODEM)) {
if (ac97_codecs[dev->model].modem_flags & AC97_LIN1) {
dev->regs[0x3e >> 1] |= 0x0c00;
dev->regs[0x40 >> 1] = /*4*/8000;
dev->regs[0x46 >> 1] = 0x8080;
}
if (ac97_codecs[dev->model].modem_flags & AC97_LIN2) {
dev->regs[0x3e >> 1] |= 0x3000;
dev->regs[0x42 >> 1] = /*4*/8000;
dev->regs[0x48 >> 1] = 0x8080;
}
if (ac97_codecs[dev->model].modem_flags & AC97_HSET) {
dev->regs[0x3e >> 1] |= 0xc000;
dev->regs[0x44 >> 1] = /*4*/8000;
dev->regs[0x4a >> 1] = 0x8080;
}
dev->regs[0x4c >> 1] = ac97_codecs[dev->model].gpi_mask | ac97_codecs[dev->model].gpo_mask;
dev->regs[0x4e >> 1] = 0xffff;
/* Set flags. */
dev->regs[0x3c >> 1] = (dev->codec_id << 14) | (ac97_codecs[dev->model].modem_flags & ~AC97_CIDR);
if (ac97_codecs[dev->model].modem_flags & AC97_CIDR)
dev->regs[0x56 >> 1] |= 0x2000;
if (ac97_codecs[dev->model].modem_flags & AC97_CID1)
dev->regs[0x56 >> 1] |= 0x4000;
if (ac97_codecs[dev->model].modem_flags & AC97_CID2)
dev->regs[0x56 >> 1] |= 0x8000;
}
/* Set vendor ID. */
dev->regs[0x7c >> 1] = ac97_codecs[dev->model].device->local >> 16;
@@ -510,13 +639,16 @@ ac97_codec_reset(void *priv)
/* Set vendor-specific registers. */
if (ac97_codecs[dev->model].vendor_regs) {
for (i = 0; ac97_codecs[dev->model].vendor_regs[i].index; i++) {
for (int i = 0; ac97_codecs[dev->model].vendor_regs[i].index; i++) {
if (ac97_codecs[dev->model].vendor_regs[i].page > 0)
dev->vendor_reg_pages[(ac97_codecs[dev->model].vendor_regs[i].page << 3) | (ac97_codecs[dev->model].vendor_regs[i].index >> 1)] = ac97_codecs[dev->model].vendor_regs[i].value;
else
dev->regs[ac97_codecs[dev->model].vendor_regs[i].index >> 1] = ac97_codecs[dev->model].vendor_regs[i].value;
}
}
if (flags & AC97_MODEM)
dev->gpi = dev->gpo = 0;
}
void
@@ -561,7 +693,7 @@ ac97_codec_getattn(void *priv, uint8_t reg, int *l, int *r)
uint32_t
ac97_codec_getrate(void *priv, uint8_t reg)
{
const ac97_codec_t *dev = (ac97_codec_t *) priv;
ac97_codec_t *dev = (ac97_codec_t *) priv;
/* Get configured sample rate, which is always 48000 if VRA/VRM is not set. */
uint32_t ret = dev->regs[reg >> 1];
@@ -575,6 +707,29 @@ ac97_codec_getrate(void *priv, uint8_t reg)
return ret;
}
void
ac97_codec_setgpi(void *priv, uint16_t gpi)
{
ac97_codec_t *dev = (ac97_codec_t *) priv;
ac97_codec_log("AC97 Codec %d: setgpi(%04X)\n", dev->codec_id, gpi);
/* Set status bits for sticky inputs. */
gpi &= ac97_codecs[dev->model].gpi_mask;
dev->regs[0x54 >> 1] |= (dev->gpi ^ gpi) & dev->regs[0x4c >> 1] & dev->regs[0x50 >> 1]; /* set on (transition & input & sticky) */
dev->gpi = gpi;
}
void
ac97_codec_setgpo(void *priv, uint16_t gpo)
{
ac97_codec_t *dev = (ac97_codec_t *) priv;
ac97_codec_log("AC97 Codec %d: setgpo(%04X)\n", dev->codec_id, gpo);
dev->gpo = gpo & ac97_codecs[dev->model].gpo_mask;
}
static void *
ac97_codec_init(const device_t *info)
{
@@ -603,7 +758,7 @@ ac97_codec_init(const device_t *info)
if (--ac97_codec_count == 0)
ac97_codec = NULL;
else
ac97_codec += sizeof(ac97_codec_t *);
ac97_codec++;
dev->codec_id = ac97_codec_id++;
/* Allocate vendor-specific register pages if required. */

View File

@@ -418,10 +418,10 @@ ac97_via_sgd_write(uint16_t addr, uint8_t val, void *priv)
dev->sgd_regs[addr] = val;
/* Send GPO to codec. */
/*for (uint8_t i = 0; i < (sizeof(dev->codec) / sizeof(dev->codec[0])); i++) {
for (uint8_t i = 0; i < (sizeof(dev->codec) / sizeof(dev->codec[0])); i++) {
if (dev->codec[i])
ac97_codec_setgpo(dev->codec[i], AS_U16(dev->sgd_regs[0x88]));
}*/
}
return;
case 0x8a ... 0x8b:
@@ -851,10 +851,8 @@ ac97_via_init(UNUSED(const device_t *info))
/* Set up codecs. */
ac97_codec = &dev->codec[0];
ac97_modem_codec = &dev->codec[1];
ac97_codec_count = sizeof(dev->codec) / sizeof(dev->codec[0]);
ac97_modem_codec_count = 1;
ac97_codec_id = ac97_modem_codec_id = 0;
ac97_codec_id = 0;
/* Set up SGD channels. */
for (uint8_t i = 0; i < (sizeof(dev->sgd) / sizeof(dev->sgd[0])); i++) {