summaryrefslogtreecommitdiff
path: root/sys/dev/pci/envy.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/pci/envy.c')
-rw-r--r--sys/dev/pci/envy.c151
1 files changed, 149 insertions, 2 deletions
diff --git a/sys/dev/pci/envy.c b/sys/dev/pci/envy.c
index 37079b0c769..490c224a466 100644
--- a/sys/dev/pci/envy.c
+++ b/sys/dev/pci/envy.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: envy.c,v 1.31 2009/11/02 05:54:16 ratchov Exp $ */
+/* $OpenBSD: envy.c,v 1.32 2010/02/20 16:45:28 ratchov Exp $ */
/*
* Copyright (c) 2007 Alexandre Ratchov <alex@caoua.org>
*
@@ -32,11 +32,12 @@
#include <sys/ioctl.h>
#include <sys/audioio.h>
#include <sys/malloc.h>
+#include <dev/audio_if.h>
+#include <dev/ic/ac97.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcidevs.h>
#include <dev/pci/envyvar.h>
#include <dev/pci/envyreg.h>
-#include <dev/audio_if.h>
#include <machine/bus.h>
#ifdef ENVY_DEBUG
@@ -103,12 +104,21 @@ int envy_get_port(void *, struct mixer_ctrl *);
int envy_set_port(void *, struct mixer_ctrl *);
int envy_get_props(void *);
+int envy_ac97_wait(struct envy_softc *);
+int envy_ac97_attach_codec(void *, struct ac97_codec_if *);
+int envy_ac97_read_codec(void *, u_int8_t, u_int16_t *);
+int envy_ac97_write_codec(void *, u_int8_t, u_int16_t);
+void envy_ac97_reset_codec(void *);
+enum ac97_host_flags envy_ac97_flags_codec(void *);
+
void delta_init(struct envy_softc *);
void delta_codec_write(struct envy_softc *, int, int, int);
void revo51_init(struct envy_softc *);
void revo51_codec_write(struct envy_softc *, int, int, int);
+void tremor51_init(struct envy_softc *);
+
void julia_init(struct envy_softc *);
void julia_codec_write(struct envy_softc *, int, int, int);
@@ -275,6 +285,12 @@ struct envy_card envy_cards[] = {
revo51_init,
revo51_codec_write
}, {
+ PCI_ID_CODE(0x1412, 0x2403),
+ "VIA Tremor 5.1",
+ 2, &unkenvy_codec, 6, &unkenvy_codec,
+ tremor51_init,
+ unkenvy_codec_write
+ }, {
0,
"unknown 1724-based card",
2, &unkenvy_codec, 8, &unkenvy_codec,
@@ -437,6 +453,26 @@ revo51_codec_write(struct envy_softc *sc, int dev, int addr, int data)
}
/*
+ * via tremor 5.1 specific code
+ */
+
+void
+tremor51_init(struct envy_softc *sc)
+{
+ sc->isac97 = 1;
+ sc->host_if.arg = sc;
+ sc->host_if.attach = envy_ac97_attach_codec;
+ sc->host_if.read = envy_ac97_read_codec;
+ sc->host_if.write = envy_ac97_write_codec;
+ sc->host_if.reset = envy_ac97_reset_codec;
+ sc->host_if.flags = envy_ac97_flags_codec;
+ sc->codec_flags = 0;
+
+ if (ac97_attach(&sc->host_if) != 0)
+ printf("%s: can't attach ac97\n", DEVNAME(sc));
+}
+
+/*
* esi julia specific code
*/
@@ -951,6 +987,108 @@ envy_eeprom_gpioxxx(struct envy_softc *sc, int addr)
return val;
}
+int
+envy_ac97_wait(struct envy_softc *sc)
+{
+ int timeout = 50, st;
+
+ for (;;) {
+ st = bus_space_read_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_AC97_CMD);
+ if ((st & ENVY_MT_AC97_READY) && !(st & ENVY_MT_AC97_CMD_MASK)) {
+ st = 0;
+ break;
+ }
+ if (timeout == 0) {
+ st = -1;
+ break;
+ }
+ delay(50);
+ timeout--;
+ }
+
+ return (st);
+}
+
+int
+envy_ac97_attach_codec(void *hdl, struct ac97_codec_if *codec_if)
+{
+ struct envy_softc *sc = hdl;
+
+ sc->codec_if = codec_if;
+
+ return (0);
+}
+
+int
+envy_ac97_read_codec(void *hdl, u_int8_t reg, u_int16_t *result)
+{
+ struct envy_softc *sc = hdl;
+
+ if (envy_ac97_wait(sc)) {
+ printf("%s: envy_ac97_read_codec: timed out\n", DEVNAME(sc));
+ return (-1);
+ }
+
+ bus_space_write_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_AC97_IDX, reg & 0x7f);
+ bus_space_write_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_AC97_CMD,
+ ENVY_MT_AC97_CMD_RD);
+ delay(50);
+
+ if (envy_ac97_wait(sc)) {
+ printf("%s: envy_ac97_read_codec: timed out\n", DEVNAME(sc));
+ return (-1);
+ }
+
+ *result = bus_space_read_2(sc->mt_iot, sc->mt_ioh, ENVY_MT_AC97_DATA);
+
+ return (0);
+}
+
+int
+envy_ac97_write_codec(void *hdl, u_int8_t reg, u_int16_t data)
+{
+ struct envy_softc *sc = hdl;
+
+ if (envy_ac97_wait(sc)) {
+ printf("%s: envy_ac97_write_codec: timed out\n", DEVNAME(sc));
+ return (-1);
+ }
+
+ bus_space_write_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_AC97_IDX, reg & 0x7f);
+ bus_space_write_2(sc->mt_iot, sc->mt_ioh, ENVY_MT_AC97_DATA, data);
+ bus_space_write_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_AC97_CMD,
+ ENVY_MT_AC97_CMD_WR);
+ delay(50);
+
+ return (0);
+}
+
+void
+envy_ac97_reset_codec(void *hdl)
+{
+ struct envy_softc *sc = hdl;
+
+ bus_space_write_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_AC97_CMD,
+ ENVY_MT_AC97_CMD_RST);
+ delay(50);
+ bus_space_write_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_AC97_CMD, 0);
+ delay(50);
+
+ if (envy_ac97_wait(sc)) {
+ printf("%s: envy_ac97_reset_codec: timed out\n", DEVNAME(sc));
+ }
+
+ return;
+}
+
+enum ac97_host_flags
+envy_ac97_flags_codec(void *hdl)
+{
+ struct envy_softc *sc = hdl;
+
+ return (sc->codec_flags);
+}
+
void
envy_reset(struct envy_softc *sc)
{
@@ -1617,6 +1755,9 @@ envy_query_devinfo(void *self, struct mixer_devinfo *dev)
AudioCinputs, AudioCoutputs, AudioCmonitor
};
+ if (sc->isac97)
+ return (sc->codec_if->vtbl->query_devinfo(sc->codec_if, dev));
+
if (dev->index < 0)
return ENXIO;
@@ -1706,6 +1847,9 @@ envy_get_port(void *self, struct mixer_ctrl *ctl)
struct envy_softc *sc = (struct envy_softc *)self;
int val, idx, ndev;
+ if (sc->isac97)
+ return (sc->codec_if->vtbl->mixer_get_port(sc->codec_if, ctl));
+
if (ctl->dev < ENVY_MIX_NCLASS) {
return EINVAL;
}
@@ -1747,6 +1891,9 @@ envy_set_port(void *self, struct mixer_ctrl *ctl)
struct envy_softc *sc = (struct envy_softc *)self;
int maxsrc, val, idx, ndev;
+ if (sc->isac97)
+ return (sc->codec_if->vtbl->mixer_set_port(sc->codec_if, ctl));
+
if (ctl->dev < ENVY_MIX_NCLASS) {
return EINVAL;
}