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:
parent
a0b4946276
commit
39004e693d
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=58384
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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 }
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user