summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcg <cg@FreeBSD.org>2000-03-20 15:30:50 +0000
committercg <cg@FreeBSD.org>2000-03-20 15:30:50 +0000
commiteffa7bc907a13c9166491626c1edcaa9d6598a96 (patch)
tree52fe9e3aa64125021a03319292c745ca3651bdbd
parent2a1e86107da4228384ff5e206f3bd033a6913ee7 (diff)
downloadFreeBSD-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
-rw-r--r--sys/dev/sound/pci/aureal.c2
-rw-r--r--sys/dev/sound/pci/csapcm.c2
-rw-r--r--sys/dev/sound/pci/es137x.c2
-rw-r--r--sys/dev/sound/pci/neomagic.c38
-rw-r--r--sys/dev/sound/pci/t4dwave.c2
-rw-r--r--sys/dev/sound/pcm/ac97.c197
-rw-r--r--sys/dev/sound/pcm/ac97.h44
-rw-r--r--sys/dev/sound/pcm/sound.c7
-rw-r--r--sys/dev/sound/pcm/sound.h1
9 files changed, 226 insertions, 69 deletions
diff --git a/sys/dev/sound/pci/aureal.c b/sys/dev/sound/pci/aureal.c
index 168f6b1..f6403c7 100644
--- a/sys/dev/sound/pci/aureal.c
+++ b/sys/dev/sound/pci/aureal.c
@@ -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);
diff --git a/sys/dev/sound/pci/csapcm.c b/sys/dev/sound/pci/csapcm.c
index 1388924..42a9cde 100644
--- a/sys/dev/sound/pci/csapcm.c
+++ b/sys/dev/sound/pci/csapcm.c
@@ -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);
diff --git a/sys/dev/sound/pci/es137x.c b/sys/dev/sound/pci/es137x.c
index e25a051..1fc99c9 100644
--- a/sys/dev/sound/pci/es137x.c
+++ b/sys/dev/sound/pci/es137x.c
@@ -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 */
diff --git a/sys/dev/sound/pci/neomagic.c b/sys/dev/sound/pci/neomagic.c
index 8966d82..9661e65 100644
--- a/sys/dev/sound/pci/neomagic.c
+++ b/sys/dev/sound/pci/neomagic.c
@@ -234,6 +234,18 @@ nm_waitcd(struct sc_info *sc)
}
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)
{
struct sc_info *sc = (struct sc_info *)devinfo;
@@ -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 @@ bad:
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 }
};
diff --git a/sys/dev/sound/pci/t4dwave.c b/sys/dev/sound/pci/t4dwave.c
index fbde2ff..82dc4cc 100644
--- a/sys/dev/sound/pci/t4dwave.c
+++ b/sys/dev/sound/pci/t4dwave.c
@@ -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);
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;
}
diff --git a/sys/dev/sound/pcm/ac97.h b/sys/dev/sound/pcm/ac97.h
index c93b29b..11ff139 100644
--- a/sys/dev/sound/pcm/ac97.h
+++ b/sys/dev/sound/pcm/ac97.h
@@ -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);
+
diff --git a/sys/dev/sound/pcm/sound.c b/sys/dev/sound/pcm/sound.c
index 6d9fe09..a9c0c10 100644
--- a/sys/dev/sound/pcm/sound.c
+++ b/sys/dev/sound/pcm/sound.c
@@ -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)
{
diff --git a/sys/dev/sound/pcm/sound.h b/sys/dev/sound/pcm/sound.h
index f7ec6a4..e456597 100644
--- a/sys/dev/sound/pcm/sound.h
+++ b/sys/dev/sound/pcm/sound.h
@@ -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 */
OpenPOWER on IntegriCloud