Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/dev/ic Add IDs for YMF743-S and YMF753-S.
details: https://anonhg.NetBSD.org/src/rev/63b35ed6382b
branches: trunk
changeset: 537908:63b35ed6382b
user: kent <kent%NetBSD.org@localhost>
date: Tue Oct 08 09:19:44 2002 +0000
description:
Add IDs for YMF743-S and YMF753-S.
ac97_attach(): Enable VRA/VRM if the codec is capable of them.
The struct ac97_softc keeps the clock of the codec, the basic
features flag (the value of AC97_REG_RESET), and the extended
features flag (the value of AC97_REG_EXT_AUDIO_ID).
ac97_codec_if: Add get_extcaps(), set_rate(), and set_clock()
methods.
diffstat:
sys/dev/ic/ac97.c | 187 +++++++++++++++++++++++++++++++++++++++++++++------
sys/dev/ic/ac97var.h | 7 +-
2 files changed, 171 insertions(+), 23 deletions(-)
diffs (truncated from 319 to 300 lines):
diff -r 05a43a70134d -r 63b35ed6382b sys/dev/ic/ac97.c
--- a/sys/dev/ic/ac97.c Tue Oct 08 08:57:52 2002 +0000
+++ b/sys/dev/ic/ac97.c Tue Oct 08 09:19:44 2002 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: ac97.c,v 1.27 2002/10/06 16:33:35 kent Exp $ */
+/* $NetBSD: ac97.c,v 1.28 2002/10/08 09:19:44 kent Exp $ */
/* $OpenBSD: ac97.c,v 1.8 2000/07/19 09:01:35 csapuntz Exp $ */
/*
@@ -63,7 +63,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ac97.c,v 1.27 2002/10/06 16:33:35 kent Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ac97.c,v 1.28 2002/10/08 09:19:44 kent Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -259,6 +259,7 @@
*/
struct ac97_softc {
+ /* ac97_codec_if must be at the first of ac97_softc. */
struct ac97_codec_if codec_if;
struct ac97_host_if *host_if;
@@ -267,7 +268,10 @@
int num_source_info;
enum ac97_host_flags host_flags;
-
+ unsigned int ac97_clock; /* usually 48000 */
+#define AC97_STANDARD_CLOCK 48000U
+ u_int16_t caps; /* -> AC97_REG_RESET */
+ u_int16_t ext_id; /* -> AC97_REG_EXT_AUDIO_ID */
u_int16_t shadow_reg[128];
};
@@ -277,13 +281,19 @@
int ac97_get_portnum_by_name __P((struct ac97_codec_if *, char *, char *,
char *));
void ac97_restore_shadow __P((struct ac97_codec_if *self));
+int ac97_set_rate(struct ac97_codec_if *codec_if, int target, u_long *rate);
+void ac97_set_clock(struct ac97_codec_if *codec_if, unsigned int clock);
+u_int16_t ac97_get_extcaps(struct ac97_codec_if *codec_if);
struct ac97_codec_if_vtbl ac97civ = {
- ac97_mixer_get_port,
+ ac97_mixer_get_port,
ac97_mixer_set_port,
ac97_query_devinfo,
ac97_get_portnum_by_name,
ac97_restore_shadow,
+ ac97_get_extcaps,
+ ac97_set_rate,
+ ac97_set_clock,
};
static const struct ac97_codecid {
@@ -320,6 +330,8 @@
{ AC97_CODEC_ID('T', 'R', 'A', 35), "TriTech unknown", },
{ AC97_CODEC_ID('W', 'M', 'L', 0), "Wolfson WM9704", },
{ AC97_CODEC_ID('W', 'M', 'L', 3), "Wolfson WM9707", },
+ { AC97_CODEC_ID('Y', 'M', 'H', 0), "Yamaha YMF743-S", },
+ { AC97_CODEC_ID('Y', 'M', 'H', 3), "Yamaha YMF753-S", },
{ 0x45838308, "ESS Technology ES1921", },
{ 0x83847600, "SigmaTel STAC9700", },
{ 0x83847604, "SigmaTel STAC9701/3/4/5", },
@@ -564,18 +576,19 @@
}
}
-int
+int
ac97_attach(host_if)
struct ac97_host_if *host_if;
{
struct ac97_softc *as;
struct device *sc_dev = (struct device *)host_if->arg;
int error, i, j;
- u_int16_t id1, id2, caps;
u_int32_t id;
+ u_int16_t id1, id2;
+ u_int16_t extstat, rate;
mixer_ctrl_t ctl;
const char *delim;
-
+
as = malloc(sizeof(struct ac97_softc), M_DEVBUF, M_WAITOK|M_ZERO);
if (as == NULL)
@@ -600,7 +613,7 @@
ac97_setup_defaults(as);
ac97_read(as, AC97_REG_VENDOR_ID1, &id1);
ac97_read(as, AC97_REG_VENDOR_ID2, &id2);
- ac97_read(as, AC97_REG_RESET, &caps);
+ ac97_read(as, AC97_REG_RESET, &as->caps);
id = (id1 << 16) | id2;
@@ -627,49 +640,73 @@
}
printf(" codec; ");
for (i = j = 0; i < 10; i++) {
- if (caps & (1 << i)) {
+ if (as->caps & (1 << i)) {
printf("%s%s", j? ", " : "", ac97feature[i]);
j++;
}
}
- printf("%s%s\n", j? ", " : "", ac97enhancement[(caps >> 10) & 0x1f]);
+ printf("%s%s\n", j ? ", " : "",
+ ac97enhancement[(as->caps >> 10) & 0x1f]);
- ac97_read(as, AC97_REG_EXT_AUDIO_ID, &caps);
- if (caps & (AC97_EXT_AUDIO_VRA | AC97_EXT_AUDIO_DRA
- | AC97_EXT_AUDIO_SPDIF | AC97_EXT_AUDIO_VRM
- | AC97_EXT_AUDIO_CDAC | AC97_EXT_AUDIO_SDAC
- | AC97_EXT_AUDIO_LDAC)) {
+ as->ac97_clock = AC97_STANDARD_CLOCK;
+ ac97_read(as, AC97_REG_EXT_AUDIO_ID, &as->ext_id);
+ if (as->ext_id & (AC97_EXT_AUDIO_VRA | AC97_EXT_AUDIO_DRA
+ | AC97_EXT_AUDIO_SPDIF | AC97_EXT_AUDIO_VRM
+ | AC97_EXT_AUDIO_CDAC | AC97_EXT_AUDIO_SDAC
+ | AC97_EXT_AUDIO_LDAC)) {
printf("%s:", sc_dev->dv_xname);
delim = "";
- if (caps & AC97_EXT_AUDIO_VRA) {
+ if (as->ext_id & AC97_EXT_AUDIO_VRA) {
printf("%s variable rate audio", delim);
delim = ",";
}
- if (caps & AC97_EXT_AUDIO_DRA) {
+ if (as->ext_id & AC97_EXT_AUDIO_DRA) {
printf("%s double rate output", delim);
delim = ",";
}
- if (caps & AC97_EXT_AUDIO_SPDIF) {
+ if (as->ext_id & AC97_EXT_AUDIO_SPDIF) {
printf("%s S/PDIF", delim);
delim = ",";
}
- if (caps & AC97_EXT_AUDIO_VRM) {
+ if (as->ext_id & AC97_EXT_AUDIO_VRM) {
printf("%s variable rate dedicated mic", delim);
delim = ",";
}
- if (caps & AC97_EXT_AUDIO_CDAC) {
+ if (as->ext_id & AC97_EXT_AUDIO_CDAC) {
printf("%s center DAC", delim);
delim = ",";
}
- if (caps & AC97_EXT_AUDIO_SDAC) {
+ if (as->ext_id & AC97_EXT_AUDIO_SDAC) {
printf("%s surround DAC", delim);
delim = ",";
}
- if (caps & AC97_EXT_AUDIO_LDAC) {
+ if (as->ext_id & AC97_EXT_AUDIO_LDAC) {
printf("%s LFE DAC", delim);
}
printf("\n");
+
+ /* If VRA and/or VRM capablities, enable them. */
+ if (as->ext_id & (AC97_EXT_AUDIO_VRA | AC97_EXT_AUDIO_VRM)) {
+ ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &extstat);
+ if (as->ext_id & AC97_EXT_AUDIO_VRA) {
+ extstat |= AC97_EXT_AUDIO_VRA;
+ }
+ if (as->ext_id & AC97_EXT_AUDIO_VRM) {
+ extstat |= AC97_EXT_AUDIO_VRM;
+ }
+ ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, extstat);
+
+ /* so it claims to do variable rate, let's make sure */
+ ac97_write(as, AC97_REG_PCM_FRONT_DAC_RATE, 44100);
+ ac97_read(as, AC97_REG_PCM_FRONT_DAC_RATE, &rate);
+ if (rate != 44100) {
+ /* We can't believe ext_id */
+ as->ext_id = 0;
+ printf("%s: Ignore these capabilities.\n",
+ sc_dev->dv_xname);
+ }
+ }
}
ac97_setup_source_info(as);
@@ -919,3 +956,109 @@
return (0);
}
+
+int
+ac97_set_rate(struct ac97_codec_if *codec_if, int target, u_long *rate)
+{
+ struct ac97_softc *as;
+ u_long value;
+ u_int16_t ext_stat;
+ u_int16_t actual;
+ u_int16_t power;
+ u_int16_t power_bit;
+
+ as = (struct ac97_softc *)codec_if;
+ value = *rate * AC97_STANDARD_CLOCK / as->ac97_clock;
+ ext_stat = 0;
+ /*
+ * PCM_FRONT_DAC_RATE/PCM_SURR_DAC_RATE/PCM_LFE_DAC_RATE
+ * Check VRA, DRA
+ * PCM_LR_ADC_RATE
+ * Check VRA
+ * PCM_MIC_ADC_RATE
+ * Check VRM
+ */
+ switch (target) {
+ case AC97_REG_PCM_FRONT_DAC_RATE:
+ case AC97_REG_PCM_SURR_DAC_RATE:
+ case AC97_REG_PCM_LFE_DAC_RATE:
+ power_bit = AC97_POWER_OUT;
+ if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
+ *rate = AC97_SINGLE_RATE;
+ return 0;
+ }
+ if (as->ext_id & AC97_EXT_AUDIO_DRA) {
+ ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &ext_stat);
+ if (value > 0x1ffff) {
+ return EINVAL;
+ } else if (value > 0xffff) {
+ /* Enable DRA */
+ ext_stat |= AC97_EXT_AUDIO_DRA;
+ ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, ext_stat);
+ value /= 2;
+ } else {
+ /* Disable DRA */
+ ext_stat &= ~AC97_EXT_AUDIO_DRA;
+ ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, ext_stat);
+ }
+ } else {
+ if (value > 0xffff)
+ return EINVAL;
+ }
+ break;
+ case AC97_REG_PCM_LR_ADC_RATE:
+ power_bit = AC97_POWER_IN;
+ if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
+ *rate = AC97_SINGLE_RATE;
+ return 0;
+ }
+ if (value > 0xffff)
+ return EINVAL;
+ break;
+ case AC97_REG_PCM_MIC_ADC_RATE:
+ power_bit = AC97_POWER_IN;
+ if (!(as->ext_id & AC97_EXT_AUDIO_VRM)) {
+ *rate = AC97_SINGLE_RATE;
+ return 0;
+ }
+ if (value > 0xffff)
+ return EINVAL;
+ break;
+ default:
+ printf("%s: Unknown register: 0x%x\n", __func__, target);
+ return EINVAL;
+ }
+
+ ac97_read(as, AC97_REG_POWER, &power);
+ ac97_write(as, AC97_REG_POWER, power | power_bit);
+
+ ac97_write(as, target, (u_int16_t)value);
+ ac97_read(as, target, &actual);
+ actual = (u_int32_t)actual * as->ac97_clock / AC97_STANDARD_CLOCK;
+
+ ac97_write(as, AC97_REG_POWER, power);
+ if (ext_stat & AC97_EXT_AUDIO_DRA) {
+ *rate = actual * 2;
+ } else {
+ *rate = actual;
+ }
+ return 0;
+}
+
+void
+ac97_set_clock(struct ac97_codec_if *codec_if, unsigned int clock)
+{
+ struct ac97_softc *as;
+
+ as = (struct ac97_softc *)codec_if;
+ as->ac97_clock = clock;
+}
+
+u_int16_t
+ac97_get_extcaps(struct ac97_codec_if *codec_if)
+{
+ struct ac97_softc *as;
+
+ as = (struct ac97_softc *)codec_if;
+ return as->ext_id;
+}
diff -r 05a43a70134d -r 63b35ed6382b sys/dev/ic/ac97var.h
--- a/sys/dev/ic/ac97var.h Tue Oct 08 08:57:52 2002 +0000
Home |
Main Index |
Thread Index |
Old Index