The start of AC97 volume control
This commit is contained in:
@@ -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);
|
||||
|
@@ -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)
|
||||
{
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
|
||||
|
Reference in New Issue
Block a user