summaryrefslogtreecommitdiff
path: root/sys/dev/pci
diff options
context:
space:
mode:
authorJacob Meuser <jakemsr@cvs.openbsd.org>2008-10-23 21:50:02 +0000
committerJacob Meuser <jakemsr@cvs.openbsd.org>2008-10-23 21:50:02 +0000
commit6f459ae12d184272e7ef7b3f547537bbf501f31a (patch)
tree33f295d20f143e6eaf9ae5cb909524d945af7e16 /sys/dev/pci
parent403c943deb4dc1db75d2ecc26efa828ba93697cf (diff)
S/PDIF output support in ac97(4), auich(4) and auvia(4)
from NetBSD tested by a few with no regressions. optical works for jsg@. ok ratchov@
Diffstat (limited to 'sys/dev/pci')
-rw-r--r--sys/dev/pci/auich.c142
-rw-r--r--sys/dev/pci/auvia.c139
-rw-r--r--sys/dev/pci/auviavar.h3
3 files changed, 178 insertions, 106 deletions
diff --git a/sys/dev/pci/auich.c b/sys/dev/pci/auich.c
index fde33499d53..97147001f97 100644
--- a/sys/dev/pci/auich.c
+++ b/sys/dev/pci/auich.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auich.c,v 1.75 2008/10/23 21:28:31 jakemsr Exp $ */
+/* $OpenBSD: auich.c,v 1.76 2008/10/23 21:50:01 jakemsr Exp $ */
/*
* Copyright (c) 2000,2001 Michael Shalayeff
@@ -184,6 +184,7 @@ struct auich_softc {
struct ac97_codec_if *codec_if;
struct ac97_host_if host_if;
+ int sc_spdif;
/* dma scatter-gather buffer lists */
@@ -344,6 +345,7 @@ int auich_write_codec(void *, u_int8_t, u_int16_t);
void auich_reset_codec(void *);
enum ac97_host_flags auich_flags_codec(void *);
unsigned int auich_calibrate(struct auich_softc *);
+void auich_spdif_event(void *, int);
int
auich_match(parent, match, aux)
@@ -508,6 +510,7 @@ auich_attach(parent, self, aux)
sc->host_if.write = auich_write_codec;
sc->host_if.reset = auich_reset_codec;
sc->host_if.flags = auich_flags_codec;
+ sc->host_if.spdif_event = auich_spdif_event;
if (sc->sc_dev.dv_cfdata->cf_flags & 0x0001)
sc->flags = AC97_HOST_SWAPPED_CHANNELS;
@@ -517,6 +520,7 @@ auich_attach(parent, self, aux)
bus_space_unmap(sc->iot_mix, sc->mix_ioh, mix_size);
return;
}
+ sc->codec_if->vtbl->unlock(sc->codec_if);
audio_attach_mi(&auich_hw_if, sc, &sc->sc_dev);
@@ -618,6 +622,13 @@ auich_flags_codec(void *v)
return (sc->flags);
}
+void
+auich_spdif_event(void *v, int flag)
+{
+ struct auich_softc *sc = v;
+ sc->sc_spdif = flag;
+}
+
int
auich_open(v, flags)
void *v;
@@ -627,6 +638,9 @@ auich_open(v, flags)
if (sc->sc_ac97rate == -1)
sc->sc_ac97rate = auich_calibrate(sc);
+
+ sc->codec_if->vtbl->lock(sc->codec_if);
+
return 0;
}
@@ -634,6 +648,9 @@ void
auich_close(v)
void *v;
{
+ struct auich_softc *sc = v;
+
+ sc->codec_if->vtbl->unlock(sc->codec_if);
}
void
@@ -647,57 +664,71 @@ auich_query_encoding(v, aep)
void *v;
struct audio_encoding *aep;
{
- switch (aep->index) {
- case 0:
- strlcpy(aep->name, AudioEulinear, sizeof aep->name);
- aep->encoding = AUDIO_ENCODING_ULINEAR;
- aep->precision = 8;
- aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
- return (0);
- case 1:
- strlcpy(aep->name, AudioEmulaw, sizeof aep->name);
- aep->encoding = AUDIO_ENCODING_ULAW;
- aep->precision = 8;
- aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
- return (0);
- case 2:
- strlcpy(aep->name, AudioEalaw, sizeof aep->name);
- aep->encoding = AUDIO_ENCODING_ALAW;
- aep->precision = 8;
- aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
- return (0);
- case 3:
- strlcpy(aep->name, AudioEslinear, sizeof aep->name);
- aep->encoding = AUDIO_ENCODING_SLINEAR;
- aep->precision = 8;
- aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
- return (0);
- case 4:
- strlcpy(aep->name, AudioEslinear_le, sizeof aep->name);
- aep->encoding = AUDIO_ENCODING_SLINEAR_LE;
- aep->precision = 16;
- aep->flags = 0;
- return (0);
- case 5:
- strlcpy(aep->name, AudioEulinear_le, sizeof aep->name);
- aep->encoding = AUDIO_ENCODING_ULINEAR_LE;
- aep->precision = 16;
- aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
- return (0);
- case 6:
- strlcpy(aep->name, AudioEslinear_be, sizeof aep->name);
- aep->encoding = AUDIO_ENCODING_SLINEAR_BE;
- aep->precision = 16;
- aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
- return (0);
- case 7:
- strlcpy(aep->name, AudioEulinear_be, sizeof aep->name);
- aep->encoding = AUDIO_ENCODING_ULINEAR_BE;
- aep->precision = 16;
- aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
- return (0);
- default:
- return (EINVAL);
+ struct auich_softc *sc = v;
+ if (sc->sc_spdif) {
+ switch (aep->index) {
+ case 0:
+ strlcpy(aep->name, AudioEslinear_le, sizeof aep->name);
+ aep->encoding = AUDIO_ENCODING_SLINEAR_LE;
+ aep->precision = 16;
+ aep->flags = 0;
+ return (0);
+ default:
+ return (EINVAL);
+ }
+ } else {
+ switch (aep->index) {
+ case 0:
+ strlcpy(aep->name, AudioEulinear, sizeof aep->name);
+ aep->encoding = AUDIO_ENCODING_ULINEAR;
+ aep->precision = 8;
+ aep->flags = 0;
+ return (0);
+ case 1:
+ strlcpy(aep->name, AudioEmulaw, sizeof aep->name);
+ aep->encoding = AUDIO_ENCODING_ULAW;
+ aep->precision = 8;
+ aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
+ return (0);
+ case 2:
+ strlcpy(aep->name, AudioEalaw, sizeof aep->name);
+ aep->encoding = AUDIO_ENCODING_ALAW;
+ aep->precision = 8;
+ aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
+ return (0);
+ case 3:
+ strlcpy(aep->name, AudioEslinear, sizeof aep->name);
+ aep->encoding = AUDIO_ENCODING_SLINEAR;
+ aep->precision = 8;
+ aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
+ return (0);
+ case 4:
+ strlcpy(aep->name, AudioEslinear_le, sizeof aep->name);
+ aep->encoding = AUDIO_ENCODING_SLINEAR_LE;
+ aep->precision = 16;
+ aep->flags = 0;
+ return (0);
+ case 5:
+ strlcpy(aep->name, AudioEulinear_le, sizeof aep->name);
+ aep->encoding = AUDIO_ENCODING_ULINEAR_LE;
+ aep->precision = 16;
+ aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
+ return (0);
+ case 6:
+ strlcpy(aep->name, AudioEslinear_be, sizeof aep->name);
+ aep->encoding = AUDIO_ENCODING_SLINEAR_BE;
+ aep->precision = 16;
+ aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
+ return (0);
+ case 7:
+ strlcpy(aep->name, AudioEulinear_be, sizeof aep->name);
+ aep->encoding = AUDIO_ENCODING_ULINEAR_BE;
+ aep->precision = 16;
+ aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
+ return (0);
+ default:
+ return (EINVAL);
+ }
}
}
@@ -716,6 +747,13 @@ auich_set_params(v, setmode, usemode, play, rec)
u_int16_t ext_id;
if (setmode & AUMODE_PLAY) {
+ /* only 16-bit 48kHz slinear_le if s/pdif enabled */
+ if (sc->sc_spdif &&
+ ((play->sample_rate != 48000) || (play->precision != 16) ||
+ (play->encoding != AUDIO_ENCODING_SLINEAR_LE)))
+ return (EINVAL);
+ }
+ if (setmode & AUMODE_PLAY) {
play->factor = 1;
play->sw_code = NULL;
switch(play->encoding) {
diff --git a/sys/dev/pci/auvia.c b/sys/dev/pci/auvia.c
index f6307d4a960..9a6eab62cc7 100644
--- a/sys/dev/pci/auvia.c
+++ b/sys/dev/pci/auvia.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auvia.c,v 1.42 2008/10/02 18:29:40 jakemsr Exp $ */
+/* $OpenBSD: auvia.c,v 1.43 2008/10/23 21:50:01 jakemsr Exp $ */
/* $NetBSD: auvia.c,v 1.28 2002/11/04 16:38:49 kent Exp $ */
/*-
@@ -217,6 +217,7 @@ int auvia_read_codec(void *, u_int8_t, u_int16_t *);
void auvia_reset_codec(void *);
int auvia_waitready_codec(struct auvia_softc *sc);
int auvia_waitvalid_codec(struct auvia_softc *sc);
+void auvia_spdif_event(void *, int);
const struct pci_matchid auvia_devices[] = {
{ PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C686A_AC97 },
@@ -301,6 +302,7 @@ auvia_attach(struct device *parent, struct device *self, void *aux)
sc->host_if.read = auvia_read_codec;
sc->host_if.write = auvia_write_codec;
sc->host_if.reset = auvia_reset_codec;
+ sc->host_if.spdif_event = auvia_spdif_event;
if ((r = ac97_attach(&sc->host_if)) != 0) {
printf("%s: can't attach codec (error 0x%X)\n",
@@ -341,6 +343,7 @@ auvia_attach(struct device *parent, struct device *self, void *aux)
auvia_set_port(sc, &ctl);
audio_attach_mi(&auvia_hw_if, sc, &sc->sc_dev);
+ sc->codec_if->vtbl->unlock(sc->codec_if);
}
@@ -458,9 +461,18 @@ auvia_read_codec(void *addr, u_int8_t reg, u_int16_t *val)
}
+void
+auvia_spdif_event(void *addr, int flag)
+{
+ struct auvia_softc *sc = addr;
+ sc->sc_spdif = flag;
+}
+
int
auvia_open(void *addr, int flags)
{
+ struct auvia_softc *sc = addr;
+ sc->codec_if->vtbl->lock(sc->codec_if);
return 0;
}
@@ -469,6 +481,7 @@ void
auvia_close(void *addr)
{
struct auvia_softc *sc = addr;
+ sc->codec_if->vtbl->unlock(sc->codec_if);
auvia_halt_output(sc);
auvia_halt_input(sc);
@@ -481,60 +494,74 @@ auvia_close(void *addr)
int
auvia_query_encoding(void *addr, struct audio_encoding *fp)
{
- switch (fp->index) {
- case 0:
- strlcpy(fp->name, AudioEulinear, sizeof fp->name);
- fp->encoding = AUDIO_ENCODING_ULINEAR;
- fp->precision = 8;
- fp->flags = 0;
- return (0);
- case 1:
- strlcpy(fp->name, AudioEmulaw, sizeof fp->name);
- fp->encoding = AUDIO_ENCODING_ULAW;
- fp->precision = 8;
- fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
- return (0);
- case 2:
- strlcpy(fp->name, AudioEalaw, sizeof fp->name);
- fp->encoding = AUDIO_ENCODING_ALAW;
- fp->precision = 8;
- fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
- return (0);
- case 3:
- strlcpy(fp->name, AudioEslinear, sizeof fp->name);
- fp->encoding = AUDIO_ENCODING_SLINEAR;
- fp->precision = 8;
- fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
- return (0);
- case 4:
- strlcpy(fp->name, AudioEslinear_le, sizeof fp->name);
- fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
- fp->precision = 16;
- fp->flags = 0;
- return (0);
- case 5:
- strlcpy(fp->name, AudioEulinear_le, sizeof fp->name);
- fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
- fp->precision = 16;
- fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
- return (0);
- case 6:
- strlcpy(fp->name, AudioEslinear_be, sizeof fp->name);
- fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
- fp->precision = 16;
- fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
- return (0);
- case 7:
- strlcpy(fp->name, AudioEulinear_be, sizeof fp->name);
- fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
- fp->precision = 16;
- fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
- return (0);
- default:
- return (EINVAL);
+ struct auvia_softc *sc = addr;
+
+ if (sc->sc_spdif) {
+ switch (fp->index) {
+ case 0:
+ strlcpy(fp->name, AudioEslinear_le, sizeof fp->name);
+ fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
+ fp->precision = 16;
+ fp->flags = 0;
+ return (0);
+ default:
+ return (EINVAL);
+ }
+ } else {
+ switch (fp->index) {
+ case 0:
+ strlcpy(fp->name, AudioEulinear, sizeof fp->name);
+ fp->encoding = AUDIO_ENCODING_ULINEAR;
+ fp->precision = 8;
+ fp->flags = 0;
+ return (0);
+ case 1:
+ strlcpy(fp->name, AudioEmulaw, sizeof fp->name);
+ fp->encoding = AUDIO_ENCODING_ULAW;
+ fp->precision = 8;
+ fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
+ return (0);
+ case 2:
+ strlcpy(fp->name, AudioEalaw, sizeof fp->name);
+ fp->encoding = AUDIO_ENCODING_ALAW;
+ fp->precision = 8;
+ fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
+ return (0);
+ case 3:
+ strlcpy(fp->name, AudioEslinear, sizeof fp->name);
+ fp->encoding = AUDIO_ENCODING_SLINEAR;
+ fp->precision = 8;
+ fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
+ return (0);
+ case 4:
+ strlcpy(fp->name, AudioEslinear_le, sizeof fp->name);
+ fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
+ fp->precision = 16;
+ fp->flags = 0;
+ return (0);
+ case 5:
+ strlcpy(fp->name, AudioEulinear_le, sizeof fp->name);
+ fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
+ fp->precision = 16;
+ fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
+ return (0);
+ case 6:
+ strlcpy(fp->name, AudioEslinear_be, sizeof fp->name);
+ fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
+ fp->precision = 16;
+ fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
+ return (0);
+ case 7:
+ strlcpy(fp->name, AudioEulinear_be, sizeof fp->name);
+ fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
+ fp->precision = 16;
+ fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
+ return (0);
+ default:
+ return (EINVAL);
+ }
}
}
-
void
auvia_set_params_sub(struct auvia_softc *sc, struct auvia_softc_chan *ch,
struct audio_params *p)
@@ -632,6 +659,12 @@ auvia_set_params(void *addr, int setmode, int usemode,
(p->precision != 8 && p->precision != 16))
return (EINVAL);
+ /* XXX only 16-bit 48kHz slinear_le if s/pdif enabled ? */
+ if (sc->sc_spdif &&
+ ((p->sample_rate != 48000) || (p->precision != 16) ||
+ (p->encoding != AUDIO_ENCODING_SLINEAR_LE)))
+ return (EINVAL);
+
if (AC97_IS_FIXED_RATE(codec)) {
p->sample_rate = AC97_SINGLE_RATE;
} else {
diff --git a/sys/dev/pci/auviavar.h b/sys/dev/pci/auviavar.h
index d83879ab9c4..b9a6fcbebb0 100644
--- a/sys/dev/pci/auviavar.h
+++ b/sys/dev/pci/auviavar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: auviavar.h,v 1.10 2008/10/02 18:29:40 jakemsr Exp $ */
+/* $OpenBSD: auviavar.h,v 1.11 2008/10/23 21:50:01 jakemsr Exp $ */
/* $NetBSD: auviavar.h,v 1.1 2000/03/31 04:45:29 tsarna Exp $ */
/*-
@@ -63,6 +63,7 @@ struct auvia_softc {
struct ac97_host_if host_if;
struct ac97_codec_if *codec_if;
int bufsize;
+ int sc_spdif;
struct auvia_dma *sc_dmas;