1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-18 10:35:55 +00:00

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
This commit is contained in:
Cameron Grant 2000-03-20 15:30:50 +00:00
parent a0b4946276
commit 39004e693d
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=58384
9 changed files with 226 additions and 69 deletions

View File

@ -633,7 +633,7 @@ au_pci_attach(device_t dev)
goto bad;
}
codec = ac97_create(dev, au, au_rdcd, au_wrcd);
codec = ac97_create(dev, au, NULL, au_rdcd, au_wrcd);
if (codec == NULL) goto bad;
mixer_init(d, &ac97_mixer, codec);

View File

@ -807,7 +807,7 @@ pcmcsa_attach(device_t dev)
csa_releaseres(csa, dev);
return (ENXIO);
}
codec = ac97_create(dev, csa, csa_rdcd, csa_wrcd);
codec = ac97_create(dev, csa, NULL, csa_rdcd, csa_wrcd);
if (codec == NULL)
return (ENXIO);
mixer_init(devinfo, &ac97_mixer, codec);

View File

@ -771,7 +771,7 @@ es_pci_attach(device_t dev)
device_printf(dev, "unable to initialize the card\n");
goto bad;
}
codec = ac97_create(dev, es, es1371_rdcodec, es1371_wrcodec);
codec = ac97_create(dev, es, NULL, es1371_rdcodec, es1371_wrcodec);
if (codec == NULL) goto bad;
/* our init routine does everything for us */
/* set to NULL; flag mixer_init not to run the ac97_init */

View File

@ -233,6 +233,18 @@ nm_waitcd(struct sc_info *sc)
return (nm_rd(sc, sc->ac97_status, 2) & sc->ac97_busy);
}
static u_int32_t
nm_initcd(void *devinfo)
{
struct sc_info *sc = (struct sc_info *)devinfo;
nm_wr(sc, 0x6c0, 0x01, 1);
nm_wr(sc, 0x6cc, 0x87, 1);
nm_wr(sc, 0x6cc, 0x80, 1);
nm_wr(sc, 0x6cc, 0x00, 1);
return 0;
}
static u_int32_t
nm_rdcd(void *devinfo, int regno)
{
@ -611,7 +623,7 @@ nm_pci_attach(device_t dev)
goto bad;
}
codec = ac97_create(dev, sc, nm_rdcd, nm_wrcd);
codec = ac97_create(dev, sc, nm_initcd, nm_rdcd, nm_wrcd);
if (codec == NULL) goto bad;
mixer_init(d, &ac97_mixer, codec);
@ -644,11 +656,33 @@ nm_pci_attach(device_t dev)
return ENXIO;
}
static int
nm_pci_resume(device_t dev)
{
snddev_info *d;
struct sc_info *sc;
d = device_get_softc(dev);
sc = pcm_getdevinfo(dev);
/* Reinit audio device */
if (nm_init(sc) == -1) {
device_printf(dev, "unable to reinitialize the card\n");
return ENXIO;
}
/* Reinit mixer */
if (mixer_reinit(d) == -1) {
device_printf(dev, "unable to reinitialize the mixer\n");
return ENXIO;
}
return 0;
}
static device_method_t nm_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, nm_pci_probe),
DEVMETHOD(device_attach, nm_pci_attach),
DEVMETHOD(device_resume, nm_pci_resume),
{ 0, 0 }
};

View File

@ -628,7 +628,7 @@ tr_pci_attach(device_t dev)
goto bad;
}
codec = ac97_create(dev, tr, tr_rdcd, tr_wrcd);
codec = ac97_create(dev, tr, NULL, tr_rdcd, tr_wrcd);
if (codec == NULL) goto bad;
mixer_init(d, &ac97_mixer, codec);

View File

@ -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;
}

View File

@ -26,10 +26,52 @@
* $FreeBSD$
*/
#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_REGEXT_ID 0x28
#define AC97_EXTCAP_VRA (1 << 0)
#define AC97_EXTCAP_DRA (1 << 1)
#define AC97_EXTCAP_VRM (1 << 3)
#define AC97_EXTCAPS (AC97_EXTCAP_VRA | AC97_EXTCAP_DRA | AC97_EXTCAP_VRM)
#define AC97_REGEXT_STAT 0x2a
#define AC97_REGEXT_FDACRATE 0x2c
#define AC97_REGEXT_SDACRATE 0x2e
#define AC97_REGEXT_LDACRATE 0x30
#define AC97_REGEXT_LADCRATE 0x32
#define AC97_REGEXT_MADCRATE 0x34
#define AC97_MIXEXT_CLFE 0x36
#define AC97_MIXEXT_SURROUND 0x38
#define AC97_REG_ID1 0x7c
#define AC97_REG_ID2 0x7e
typedef u_int32_t (ac97_init)(void *devinfo);
typedef u_int32_t (ac97_read)(void *devinfo, int regno);
typedef void (ac97_write)(void *devinfo, int regno, u_int32_t data);
extern snd_mixer ac97_mixer;
struct ac97_info;
struct ac97_info *ac97_create(device_t dev, void *devinfo, ac97_read *rd, ac97_write *wr);
struct ac97_info *ac97_create(device_t dev, void *devinfo, ac97_init *init,
ac97_read *rd, ac97_write *wr);
int ac97_setrate(struct ac97_info *codec, int which, int rate);
int ac97_setextmode(struct ac97_info *codec, u_int16_t mode);

View File

@ -143,6 +143,13 @@ pcm_setflags(device_t dev, u_int32_t val)
d->flags = val;
}
void *
pcm_getdevinfo(device_t dev)
{
snddev_info *d = device_get_softc(dev);
return d->devinfo;
}
void
pcm_setswap(device_t dev, pcm_swap_t *swap)
{

View File

@ -157,6 +157,7 @@ int pcm_register(device_t dev, void *devinfo, int numplay, int numrec);
int pcm_setstatus(device_t dev, char *str);
u_int32_t pcm_getflags(device_t dev);
void pcm_setflags(device_t dev, u_int32_t val);
void *pcm_getdevinfo(device_t dev);
void pcm_setswap(device_t dev, pcm_swap_t *swap);
#endif /* _KERNEL */