diff options
author | cg <cg@FreeBSD.org> | 2000-03-20 15:30:50 +0000 |
---|---|---|
committer | cg <cg@FreeBSD.org> | 2000-03-20 15:30:50 +0000 |
commit | effa7bc907a13c9166491626c1edcaa9d6598a96 (patch) | |
tree | 52fe9e3aa64125021a03319292c745ca3651bdbd /sys/dev/sound/pcm/ac97.c | |
parent | 2a1e86107da4228384ff5e206f3bd033a6913ee7 (diff) | |
download | FreeBSD-src-effa7bc907a13c9166491626c1edcaa9d6598a96.zip FreeBSD-src-effa7bc907a13c9166491626c1edcaa9d6598a96.tar.gz |
update the ac97 layer:
* add a callback for initialising the mixer interface
* support ac97 2.1 variable rate audio feature
fix ac97-using drivers for the above
add suspend/resume support for neomagic
Diffstat (limited to 'sys/dev/sound/pcm/ac97.c')
-rw-r--r-- | sys/dev/sound/pcm/ac97.c | 197 |
1 files changed, 135 insertions, 62 deletions
diff --git a/sys/dev/sound/pcm/ac97.c b/sys/dev/sound/pcm/ac97.c index e0ddad7..93d5843 100644 --- a/sys/dev/sound/pcm/ac97.c +++ b/sys/dev/sound/pcm/ac97.c @@ -29,30 +29,6 @@ #include <dev/sound/pcm/sound.h> #include <dev/sound/pcm/ac97.h> -#define AC97_MUTE 0x8000 - -#define AC97_REG_RESET 0x00 -#define AC97_MIX_MASTER 0x02 -#define AC97_MIX_PHONES 0x04 -#define AC97_MIX_MONO 0x06 -#define AC97_MIX_TONE 0x08 -#define AC97_MIX_BEEP 0x0a -#define AC97_MIX_PHONE 0x0c -#define AC97_MIX_MIC 0x0e -#define AC97_MIX_LINE 0x10 -#define AC97_MIX_CD 0x12 -#define AC97_MIX_VIDEO 0x14 -#define AC97_MIX_AUX 0x16 -#define AC97_MIX_PCM 0x18 -#define AC97_REG_RECSEL 0x1a -#define AC97_MIX_RGAIN 0x1c -#define AC97_MIX_MGAIN 0x1e -#define AC97_REG_GEN 0x20 -#define AC97_REG_3D 0x22 -#define AC97_REG_POWER 0x26 -#define AC97_REG_ID1 0x7c -#define AC97_REG_ID2 0x7e - struct ac97mixtable_entry { int reg:8; unsigned bits:4; @@ -65,12 +41,13 @@ struct ac97mixtable_entry { struct ac97_info { device_t dev; + ac97_init *init; ac97_read *read; ac97_write *write; void *devinfo; char id[4]; char rev; - unsigned caps, se; + unsigned caps, se, extcaps, extid, extstat; struct ac97mixtable_entry mix[32]; }; @@ -162,6 +139,75 @@ static char *ac97feature[] = { "20 bit ADC" }; +static char *ac97extfeature[] = { + "variable rate PCM", + "double rate PCM", + "reserved 1", + "variable rate mic", + "reserved 2", + "reserved 3", + "center DAC", + "surround DAC", + "LFE DAC", + "AMAP", + "reserved 4", + "reserved 5", + "reserved 6", + "reserved 7", +}; + +static u_int16_t +rdcd(struct ac97_info *codec, int reg) +{ + return codec->read(codec->devinfo, reg); +} + +static void +wrcd(struct ac97_info *codec, int reg, u_int16_t val) +{ + codec->write(codec->devinfo, reg, val); +} + +int +ac97_setrate(struct ac97_info *codec, int which, int rate) +{ + u_int16_t v; + + switch(which) { + case AC97_REGEXT_FDACRATE: + case AC97_REGEXT_SDACRATE: + case AC97_REGEXT_LDACRATE: + case AC97_REGEXT_LADCRATE: + case AC97_REGEXT_MADCRATE: + break; + + default: + return -1; + } + + if (rate != 0) { + v = rate; + if (codec->extstat & AC97_EXTCAP_DRA) + v >>= 1; + wrcd(codec, which, v); + } + v = rdcd(codec, which); + if (codec->extstat & AC97_EXTCAP_DRA) + v <<= 1; + return v; +} + +int +ac97_setextmode(struct ac97_info *codec, u_int16_t mode) +{ + mode &= AC97_EXTCAPS; + if ((mode & ~codec->extcaps) != 0) + return -1; + wrcd(codec, AC97_REGEXT_STAT, mode); + codec->extstat = rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS; + return (mode == codec->extstat)? 0 : -1; +} + static int ac97_setrecsrc(struct ac97_info *codec, int channel) { @@ -169,9 +215,10 @@ ac97_setrecsrc(struct ac97_info *codec, int channel) if (e->recidx > 0) { int val = e->recidx - 1; val |= val << 8; - codec->write(codec->devinfo, AC97_REG_RECSEL, val); + wrcd(codec, AC97_REG_RECSEL, val); return 0; - } else return -1; + } else + return -1; } static int @@ -181,7 +228,8 @@ ac97_setmixer(struct ac97_info *codec, unsigned channel, unsigned left, unsigned if (e->reg != 0) { int max, val, reg = (e->reg >= 0)? e->reg : -e->reg; - if (!e->stereo) right = left; + if (!e->stereo) + right = left; if (e->reg > 0) { left = 100 - left; right = 100 - right; @@ -205,14 +253,16 @@ ac97_setmixer(struct ac97_info *codec, unsigned channel, unsigned left, unsigned val &= max; val <<= e->ofs; if (e->mask) { - int cur = codec->read(codec->devinfo, e->reg); + int cur = rdcd(codec, e->reg); val |= cur & ~(max << e->ofs); } } - if (left == 0 && right == 0 && e->mute == 1) val = AC97_MUTE; - codec->write(codec->devinfo, reg, val); + if (left == 0 && right == 0 && e->mute == 1) + val = AC97_MUTE; + wrcd(codec, reg, val); return left | (right << 8); - } else return -1; + } else + return -1; } #if 0 @@ -224,8 +274,9 @@ ac97_getmixer(struct ac97_info *codec, int channel) int max, val, volume; max = (1 << e->bits) - 1; - val = codec->read(codec->devinfo, e->reg); - if (val == AC97_MUTE && e->mute == 1) volume = 0; + val = rdcd(code, e->reg); + if (val == AC97_MUTE && e->mute == 1) + volume = 0; else { if (e->stereo == 0) val >>= e->ofs; val &= max; @@ -233,65 +284,83 @@ ac97_getmixer(struct ac97_info *codec, int channel) if (e->reg > 0) volume = 100 - volume; } return volume; - } else return -1; + } else + return -1; } #endif static unsigned -ac97_init(struct ac97_info *codec) +ac97_initmixer(struct ac97_info *codec) { unsigned i, j; u_int32_t id; - for (i = 0; i < 32; i++) codec->mix[i] = ac97mixtable_default[i]; + for (i = 0; i < 32; i++) + codec->mix[i] = ac97mixtable_default[i]; - codec->write(codec->devinfo, AC97_REG_POWER, 0); - codec->write(codec->devinfo, AC97_REG_RESET, 0); + if (codec->init) + codec->init(codec->devinfo); + wrcd(codec, AC97_REG_POWER, 0); + wrcd(codec, AC97_REG_RESET, 0); DELAY(10000); - i = codec->read(codec->devinfo, AC97_REG_RESET); + i = rdcd(codec, AC97_REG_RESET); codec->caps = i & 0x03ff; codec->se = (i & 0x7c00) >> 10; - id = (codec->read(codec->devinfo, AC97_REG_ID1) << 16) | - codec->read(codec->devinfo, AC97_REG_ID2); + i = rdcd(codec, AC97_REGEXT_ID); + codec->extcaps = i & 0x3fff; + codec->extid = (i & 0xc000) >> 14; + + codec->extstat = rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS; + + id = (rdcd(codec, AC97_REG_ID1) << 16) | rdcd(codec, AC97_REG_ID2); codec->rev = id & 0x000000ff; - codec->write(codec->devinfo, AC97_MIX_MASTER, 0x20); - if ((codec->read(codec->devinfo, AC97_MIX_MASTER) & 0x20) == 0x20) + wrcd(codec, AC97_MIX_MASTER, 0x20); + if ((rdcd(codec, AC97_MIX_MASTER) & 0x20) == 0x20) codec->mix[SOUND_MIXER_VOLUME].bits++; - codec->write(codec->devinfo, AC97_MIX_MASTER, 0x00); + wrcd(codec, AC97_MIX_MASTER, 0x00); if (bootverbose) { device_printf(codec->dev, "ac97 codec id 0x%8x", id); - for (i = 0; ac97codecid[i].id; i++) { - if (ac97codecid[i].id == id) printf(" (%s)", ac97codecid[i].name); - } + for (i = 0; ac97codecid[i].id; i++) + if (ac97codecid[i].id == id) + printf(" (%s)", ac97codecid[i].name); printf("\n"); device_printf(codec->dev, "ac97 codec features "); - for (i = j = 0; i < 10; i++) { - if (codec->caps & (1 << i)) { - printf("%s%s", j? ", " : "", ac97feature[i]); - j++; - } - } - printf("%s%d bit master volume", j? ", " : "", codec->mix[SOUND_MIXER_VOLUME].bits); + for (i = j = 0; i < 10; i++) + if (codec->caps & (1 << i)) + printf("%s%s", j++? ", " : "", ac97feature[i]); + printf("%s%d bit master volume", j++? ", " : "", codec->mix[SOUND_MIXER_VOLUME].bits); printf("%s%s\n", j? ", " : "", ac97enhancement[codec->se]); + + if (codec->extcaps != 0 || codec->extid) { + device_printf(codec->dev, "ac97 %s codec", + codec->extid? "secondary" : "primary"); + if (codec->extcaps) + printf(" extended features "); + for (i = j = 0; i < 14; i++) + if (codec->extcaps & (1 << i)) + printf("%s%s", j++? ", " : "", ac97extfeature[i]); + printf("\n"); + } } - if ((codec->read(codec->devinfo, AC97_REG_POWER) & 2) == 0) + if ((rdcd(codec, AC97_REG_POWER) & 2) == 0) device_printf(codec->dev, "ac97 codec reports dac not ready\n"); return 0; } struct ac97_info * -ac97_create(device_t dev, void *devinfo, ac97_read *rd, ac97_write *wr) +ac97_create(device_t dev, void *devinfo, ac97_init *init, ac97_read *rd, ac97_write *wr) { struct ac97_info *codec; codec = (struct ac97_info *)malloc(sizeof *codec, M_DEVBUF, M_NOWAIT); if (codec != NULL) { codec->dev = dev; + codec->init = init; codec->read = rd; codec->write = wr; codec->devinfo = devinfo; @@ -303,8 +372,9 @@ static int ac97mix_init(snd_mixer *m) { struct ac97_info *codec = mix_getdevinfo(m); - if (codec == NULL) return -1; - ac97_init(codec); + if (codec == NULL) + return -1; + ac97_initmixer(codec); mix_setdevs(m, ac97mixdevs | ((codec->caps & 4)? SOUND_MASK_BASS | SOUND_MASK_TREBLE : 0)); mix_setrecdevs(m, ac97recdevs); return 0; @@ -314,7 +384,8 @@ static int ac97mix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right) { struct ac97_info *codec = mix_getdevinfo(m); - if (codec == NULL) return -1; + if (codec == NULL) + return -1; return ac97_setmixer(codec, dev, left, right); } @@ -323,9 +394,11 @@ ac97mix_setrecsrc(snd_mixer *m, u_int32_t src) { int i; struct ac97_info *codec = mix_getdevinfo(m); - if (codec == NULL) return -1; + if (codec == NULL) + return -1; for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) - if ((src & (1 << i)) != 0) break; + if ((src & (1 << i)) != 0) + break; return (ac97_setrecsrc(codec, i) == 0)? 1 << i : -1; } |