diff --git a/src/include/86box/snd_ac97.h b/src/include/86box/snd_ac97.h index a72a874d9..8b5e89920 100644 --- a/src/include/86box/snd_ac97.h +++ b/src/include/86box/snd_ac97.h @@ -19,8 +19,8 @@ typedef struct { - uint32_t id; - uint8_t regs[128]; + uint32_t vendor_id; + uint8_t codec_id, regs[128]; } ac97_codec_t; @@ -40,7 +40,8 @@ extern void ac97_via_remap_modem_codec(void *priv, uint16_t new_io_base, uint8_t #ifdef EMU_DEVICE_H extern ac97_codec_t **ac97_codec, **ac97_modem_codec; -extern int ac97_codec_count, ac97_modem_codec_count; +extern int ac97_codec_count, ac97_modem_codec_count, + ac97_codec_id, ac97_modem_codec_id; extern const device_t alc100_device; extern const device_t cs4297_device; diff --git a/src/sound/snd_ac97_codec.c b/src/sound/snd_ac97_codec.c index 5532a1441..133b9f0c5 100644 --- a/src/sound/snd_ac97_codec.c +++ b/src/sound/snd_ac97_codec.c @@ -55,16 +55,14 @@ ac97_codec_log(const char *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 -}; -static const int32_t codec_gain[] = { - 8545, 8552, 8561, 8571, 8585, 8602, 8623, 8650, 8684, 8726, 8780, 8847, 8932, 9039, 9173, 9342, - 9556, 9824, 10161, 10587, 11122, 11796, 12645, 13712, 15057, 16750, 18882, 21564, 24942, 29194, 34547, 41287 + 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, + 41305, 52068, 65636, 82739, 104299, 131477, 165737, 208925 }; ac97_codec_t **ac97_codec = NULL, **ac97_modem_codec = NULL; -int ac97_codec_count = 0, ac97_modem_codec_count = 0; +int ac97_codec_count = 0, ac97_modem_codec_count = 0, + ac97_codec_id = 0, ac97_modem_codec_id = 0; uint8_t @@ -72,7 +70,7 @@ ac97_codec_read(ac97_codec_t *dev, uint8_t reg) { uint8_t ret = dev->regs[reg & 0x7f]; - ac97_codec_log("AC97 Codec: read(%02X) = %02X\n", reg, ret); + ac97_codec_log("AC97 Codec %d: read(%02X) = %02X\n", dev->codec_id, reg, ret); return ret; } @@ -81,7 +79,7 @@ ac97_codec_read(ac97_codec_t *dev, uint8_t reg) void ac97_codec_write(ac97_codec_t *dev, uint8_t reg, uint8_t val) { - ac97_codec_log("AC97 Codec: write(%02X, %02X)\n", reg, val); + ac97_codec_log("AC97 Codec %d: write(%02X, %02X)\n", dev->codec_id, reg, val); reg &= 0x7f; @@ -108,9 +106,16 @@ ac97_codec_write(ac97_codec_t *dev, uint8_t reg, uint8_t val) case 0x03: /* Master Volume MSB */ case 0x05: /* Aux Out Volume MSB */ val &= 0xbf; + + /* Convert 6-bit level 1xxxxx to 011111 per specification. */ + if (val & 0x20) { + val &= ~0x20; + val |= 0x1f; + } break; case 0x07: /* Mono Volume MSB */ + case 0x0b: /* PC Beep Volume MSB */ case 0x20: /* General Purpose LSB */ val &= 0x80; break; @@ -118,12 +123,17 @@ ac97_codec_write(ac97_codec_t *dev, uint8_t reg, uint8_t val) case 0x02: /* Master Volume LSB */ case 0x04: /* Aux Out Volume LSB */ case 0x06: /* Mono Volume LSB */ - case 0x0b: /* PC Beep Volume MSB */ val &= 0x3f; + + /* Convert 6-bit level 1xxxxx to 011111 per specification. */ + if (val & 0x20) { + val &= ~0x20; + val |= 0x1f; + } break; case 0x0a: /* PC Beep Volume LSB */ - val &= 0xfe; + val &= 0x1e; break; case 0x0c: /* Phone Volume LSB */ @@ -173,7 +183,7 @@ ac97_codec_reset(void *priv) { ac97_codec_t *dev = (ac97_codec_t *) priv; - ac97_codec_log("AC97 Codec: reset()\n"); + ac97_codec_log("AC97 Codec %d: reset()\n", dev->codec_id); memset(dev->regs, 0, sizeof(dev->regs)); @@ -183,11 +193,12 @@ ac97_codec_reset(void *priv) /* Flag codec as ready. */ dev->regs[0x26] = 0x0f; - /* Set Vendor ID. */ - dev->regs[0x7c] = dev->id >> 16; - dev->regs[0x7d] = dev->id >> 24; - dev->regs[0x7e] = dev->id; - dev->regs[0x7f] = dev->id >> 8; + /* Set Codec and Vendor IDs. */ + dev->regs[0x29] = (dev->codec_id << 6) | 0x02; + dev->regs[0x7c] = dev->vendor_id >> 16; + dev->regs[0x7d] = dev->vendor_id >> 24; + dev->regs[0x7e] = dev->vendor_id; + dev->regs[0x7f] = dev->vendor_id >> 8; } @@ -204,18 +215,14 @@ ac97_codec_getattn(void *priv, uint8_t reg, int *l, int *r) 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)]; + l_val &= 0x1f; + r_val &= 0x1f; + if (reg < 0x10) { /* 5-bit level (converted from 6-bit on register write) */ + *l = codec_attn[0x1f - l_val]; + *r = codec_attn[0x1f - r_val]; } else { /* 5-bit gain */ - *l = codec_gain[0x1f - (l_val & 0x1f)]; - *r = codec_gain[0x1f - (r_val & 0x1f)]; + *l = codec_attn[0x27 - l_val]; + *r = codec_attn[0x27 - r_val]; } } @@ -226,19 +233,20 @@ ac97_codec_init(const device_t *info) ac97_codec_t *dev = malloc(sizeof(ac97_codec_t)); memset(dev, 0, sizeof(ac97_codec_t)); - dev->id = info->local; - ac97_codec_log("AC97 Codec: init(%c%c%c%02X)\n", (dev->id >> 24) & 0xff, (dev->id >> 16) & 0xff, (dev->id >> 8) & 0xff, dev->id & 0xff); + dev->vendor_id = info->local; + ac97_codec_log("AC97 Codec %d: init(%c%c%c%02X)\n", ac97_codec_id, (dev->vendor_id >> 24) & 0xff, (dev->vendor_id >> 16) & 0xff, (dev->vendor_id >> 8) & 0xff, dev->vendor_id & 0xff); /* Associate this codec to the current controller. */ if (!ac97_codec || (ac97_codec_count <= 0)) { - fatal("AC97 Codec: No controller to associate codec"); - return NULL; + fatal("AC97 Codec %d: No controller to associate codec\n", ac97_codec_id); + return NULL; } *ac97_codec = dev; if (--ac97_codec_count == 0) ac97_codec = NULL; else ac97_codec += sizeof(ac97_codec_t *); + dev->codec_id = ac97_codec_id++; return dev; } @@ -249,7 +257,7 @@ ac97_codec_close(void *priv) { ac97_codec_t *dev = (ac97_codec_t *) priv; - ac97_codec_log("AC97 Codec: close()\n"); + ac97_codec_log("AC97 Codec %d: close()\n", dev->codec_id); free(dev); } diff --git a/src/sound/snd_ac97_via.c b/src/sound/snd_ac97_via.c index bc2ec8ee9..a83ddc17a 100644 --- a/src/sound/snd_ac97_via.c +++ b/src/sound/snd_ac97_via.c @@ -750,6 +750,7 @@ ac97_via_init(const device_t *info) ac97_codec = &dev->codec[0][0]; ac97_modem_codec = &dev->codec[1][0]; ac97_codec_count = ac97_modem_codec_count = sizeof(dev->codec[0]) / sizeof(dev->codec[0][0]); + ac97_codec_id = ac97_modem_codec_id = 0; /* Set up SGD channels. */ for (uint8_t i = 0; i < (sizeof(dev->sgd) / sizeof(dev->sgd[0])); i++) { diff --git a/src/sound/snd_audiopci.c b/src/sound/snd_audiopci.c index cd8288d4d..886ab4ff2 100644 --- a/src/sound/snd_audiopci.c +++ b/src/sound/snd_audiopci.c @@ -1338,7 +1338,8 @@ static void *es1371_init(const device_t *info) ac97_codec = &es1371->codec; ac97_codec_count = 1; - if (!info->local) + ac97_codec_id = 0; + if (!info->local) /* let the machine decide the codec on onboard implementations */ device_add(&cs4297a_device); return es1371;