The start of AC97 volume control

This commit is contained in:
RichardG867
2021-07-26 00:19:39 -03:00
parent 42eada3122
commit 70285df61b
4 changed files with 74 additions and 44 deletions

View File

@@ -27,6 +27,7 @@ typedef struct {
extern uint8_t ac97_codec_read(ac97_codec_t *dev, uint8_t reg);
extern void ac97_codec_write(ac97_codec_t *dev, uint8_t reg, uint8_t val);
extern void ac97_codec_reset(void *priv);
extern void ac97_codec_getattn(void *priv, uint8_t reg, int *l, int *r);
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);

View File

@@ -54,6 +54,11 @@ ac97_codec_log(const char *fmt, ...)
#define ac97_codec_log(fmt, ...)
#endif
static const int32_t codec_attn[] = {
25, 32, 41, 51, 65, 82, 103, 130, 164, 206, 260, 327, 412, 519, 653, 822,
1036, 1304, 1641, 2067, 2602, 3276, 4125, 5192, 6537, 8230, 10362, 13044, 16422, 20674, 26027, 32767
};
ac97_codec_t **ac97_codec = NULL, **ac97_modem_codec = NULL;
int ac97_codec_count = 0, ac97_modem_codec_count = 0;
@@ -182,6 +187,35 @@ ac97_codec_reset(void *priv)
}
void
ac97_codec_getattn(void *priv, uint8_t reg, int *l, int *r)
{
ac97_codec_t *dev = (ac97_codec_t *) priv;
uint8_t r_val = dev->regs[reg],
l_val = dev->regs[reg | 1];
if (l_val & 0x80) { /* mute */
*l = 0;
*r = 0;
return;
}
if (reg < 0x10) { /* 6-bit volume */
if (l_val & 0x20)
*l = codec_attn[0];
else
*l = codec_attn[0x1f - (l_val & 0x1f)];
if (r_val & 0x20)
*r = codec_attn[0];
else
*r = codec_attn[0x1f - (r_val & 0x1f)];
} else { /* 5-bit gain */
*l = codec_attn[0x1f - (l_val & 0x1f)];
*r = codec_attn[0x1f - (r_val & 0x1f)];
}
}
static void *
ac97_codec_init(const device_t *info)
{

View File

@@ -59,12 +59,12 @@ typedef struct _ac97_via_ {
pc_timer_t timer_count, timer_count_fm;
uint64_t timer_latch, timer_fifo_latch;
int16_t out_l, out_r, fm_out_l, fm_out_r;
double cd_vol_l, cd_vol_r;
int16_t buffer[SOUNDBUFLEN * 2], fm_buffer[SOUNDBUFLEN * 2];
int master_vol_l, master_vol_r, pcm_vol_l, pcm_vol_r, cd_vol_l, cd_vol_r;
int32_t buffer[SOUNDBUFLEN * 2], fm_buffer[SOUNDBUFLEN * 2];
int pos, fm_pos;
} ac97_via_t;
#define ENABLE_AC97_VIA_LOG 1
#ifdef ENABLE_AC97_VIA_LOG
int ac97_via_do_log = ENABLE_AC97_VIA_LOG;
@@ -85,6 +85,7 @@ ac97_via_log(const char *fmt, ...)
static void ac97_via_sgd_process(void *priv);
static void ac97_via_update_volumes(ac97_via_t *dev, ac97_codec_t *codec);
void
@@ -125,11 +126,15 @@ ac97_via_write_control(void *priv, uint8_t modem, uint8_t val)
ac97_via_log("AC97 VIA %d: write_control(%02X)\n", modem, val);
/* Reset codecs if requested. */
if (val & 0x40) {
for (i = 0; i <= 1; i++) {
if (dev->codec[modem][i])
/* Reset and/or update volumes on all codecs. */
for (i = 0; i <= 1; i++) {
if (dev->codec[modem][i]) {
/* Reset codec if requested. */
if (val & 0x40)
ac97_codec_reset(dev->codec[modem][i]);
/* Update volumes. */
ac97_via_update_volumes(dev, dev->codec[modem][i]);
}
}
@@ -168,6 +173,16 @@ ac97_via_update_irqs(ac97_via_t *dev)
}
static void
ac97_via_update_volumes(ac97_via_t *dev, ac97_codec_t *codec) {
ac97_codec_getattn(codec, 0x02, &dev->master_vol_l, &dev->master_vol_r);
ac97_codec_getattn(codec, 0x18, &dev->pcm_vol_l, &dev->pcm_vol_r);
ac97_codec_getattn(codec, 0x12, &dev->cd_vol_l, &dev->cd_vol_r);
pclog("master %d %d\npcm %d %d\ncd %d %d\n", dev->master_vol_l, dev->master_vol_r, dev->pcm_vol_l, dev->pcm_vol_r, dev->cd_vol_l, dev->cd_vol_r);
}
uint8_t
ac97_via_sgd_read(uint16_t addr, void *priv)
{
@@ -361,6 +376,9 @@ ac97_via_sgd_write(uint16_t addr, uint8_t val, void *priv)
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]);
/* Update volumes. */
ac97_via_update_volumes(dev, codec);
}
/* Flag data/status/index for this codec as valid. */
@@ -479,9 +497,12 @@ ac97_via_remap_modem_codec(void *priv, uint16_t new_io_base, uint8_t enable)
static void
ac97_via_update(ac97_via_t *dev)
{
int32_t l = (((dev->out_l * dev->pcm_vol_l) >> 15) * dev->master_vol_l) >> 15,
r = (((dev->out_r * dev->pcm_vol_r) >> 15) * dev->master_vol_r) >> 15;
for (; dev->pos < sound_pos_global; dev->pos++) {
dev->buffer[dev->pos*2] = dev->out_l;
dev->buffer[dev->pos*2 + 1] = dev->out_r;
dev->buffer[dev->pos*2] = l;
dev->buffer[dev->pos*2 + 1] = r;
}
}
@@ -701,10 +722,9 @@ ac97_via_get_buffer(int32_t *buffer, int len, void *priv)
for (int c = 0; c < len * 2; c++) {
buffer[c] += dev->buffer[c] / 2;
buffer[c] += dev->fm_buffer[c];
buffer[c] += dev->fm_buffer[c] / 2;
}
/* Feed silence if the FIFO is empty. */
dev->pos = dev->fm_pos = 0;
}

View File

@@ -148,12 +148,6 @@ typedef struct {
#define FORMAT_MONO_16 2
#define FORMAT_STEREO_16 3
const int32_t codec_attn[]= {
25,32,41,51,65,82,103,130,164,206,260,327,412,519,653,
822,1036,1304,1641,2067,2602,3276,4125,5192,6537,8230,10362,13044,
16422,20674,26027,32767
};
static void es1371_fetch(es1371_t *es1371, int dac_nr);
static void update_legacy(es1371_t *es1371, uint32_t old_legacy_ctrl);
@@ -595,35 +589,16 @@ static void es1371_outl(uint16_t port, uint32_t val, void *p)
case 0x14:
if (val & CODEC_READ) {
es1371->codec_ctrl &= 0x00ff0000;
es1371->codec_ctrl |= ac97_codec_read(es1371->codec, (val >> 16) & 0x7f);
es1371->codec_ctrl |= ac97_codec_read(es1371->codec, ((val >> 16) & 0x7f) + 1) << 8;
val = (val >> 16) & 0x7e;
es1371->codec_ctrl |= ac97_codec_read(es1371->codec, val);
es1371->codec_ctrl |= ac97_codec_read(es1371->codec, val | 1) << 8;
} else {
es1371->codec_ctrl &= 0x00ffffff;
ac97_codec_write(es1371->codec, (val >> 16) & 0x7f, val & 0xff);
ac97_codec_write(es1371->codec, ((val >> 16) & 0x7f) + 1, val >> 8);
es1371->codec_ctrl = val & 0x00ffffff;
ac97_codec_write(es1371->codec, (val >> 16) & 0x7e, val & 0xff);
ac97_codec_write(es1371->codec, ((val >> 16) & 0x7e) | 1, val >> 8);
val = *((uint16_t *) &es1371->codec->regs[0x02]); /* Master Volume */
if (val & 0x8000) {
es1371->master_vol_l = es1371->master_vol_r = 0;
} else {
if (val & 0x2000)
es1371->master_vol_l = codec_attn[0];
else
es1371->master_vol_l = codec_attn[0x1f - ((val >> 8) & 0x1f)];
if (val & 0x20)
es1371->master_vol_r = codec_attn[0];
else
es1371->master_vol_r = codec_attn[0x1f - (val & 0x1f)];
}
val = *((uint16_t *) &es1371->codec->regs[0x12]); /* CD Volume */
if (val & 0x8000) {
es1371->cd_vol_l = es1371->cd_vol_r = 0;
} else {
es1371->cd_vol_l = codec_attn[0x1f - ((val >> 8) & 0x1f)];
es1371->cd_vol_r = codec_attn[0x1f - (val & 0x1f)];
}
break;
ac97_codec_getattn(es1371->codec, 0x02, &es1371->master_vol_l, &es1371->master_vol_r);
ac97_codec_getattn(es1371->codec, 0x12, &es1371->cd_vol_l, &es1371->cd_vol_r);
}
break;