summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorJacob Meuser <jakemsr@cvs.openbsd.org>2008-10-16 19:16:59 +0000
committerJacob Meuser <jakemsr@cvs.openbsd.org>2008-10-16 19:16:59 +0000
commit90aabd4ca2cee27b46f35ad2bde34bdc150da7d6 (patch)
treeecb3705ba40ce2f839fff414e3d0b2eae90c396d /sys
parentbd4e71e6bed07a52899e9b2eb7b4088e57f0a007 (diff)
Add S/PDIF support. From NetBSD.
Clean up a little while here. from Alexey Suslikov, thanks tested by several as part of a larger diff, thanks also
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/pci/azalia.c19
-rw-r--r--sys/dev/pci/azalia.h21
-rw-r--r--sys/dev/pci/azalia_codec.c43
3 files changed, 73 insertions, 10 deletions
diff --git a/sys/dev/pci/azalia.c b/sys/dev/pci/azalia.c
index 8600d3a0f82..3f7e11aa0f9 100644
--- a/sys/dev/pci/azalia.c
+++ b/sys/dev/pci/azalia.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: azalia.c,v 1.59 2008/10/12 10:42:38 jakemsr Exp $ */
+/* $OpenBSD: azalia.c,v 1.60 2008/10/16 19:16:58 jakemsr Exp $ */
/* $NetBSD: azalia.c,v 1.20 2006/05/07 08:31:44 kent Exp $ */
/*-
@@ -36,7 +36,6 @@
*
*
* TO DO:
- * - S/PDIF
* - power hook
* - multiple codecs (needed?)
* - multiple streams (needed?)
@@ -1513,6 +1512,7 @@ int
azalia_codec_connect_stream(codec_t *this, int dir, uint16_t fmt, int number)
{
const convgroup_t *group;
+ uint32_t v;
int i, err, startchan, nchan;
nid_t nid;
boolean_t flag222;
@@ -1550,6 +1550,14 @@ azalia_codec_connect_stream(codec_t *this, int dir, uint16_t fmt, int number)
stream_chan, NULL);
if (err)
goto exit;
+ if (this->w[nid].widgetcap & COP_AWCAP_DIGITAL) {
+ /* enable S/PDIF */
+ this->comresp(this, nid, CORB_GET_DIGITAL_CONTROL,
+ 0, &v);
+ v = (v & 0xff) | CORB_DCC_DIGEN;
+ this->comresp(this, nid, CORB_SET_DIGITAL_CONTROL_L,
+ v, NULL);
+ }
startchan += WIDGET_CHANNELS(&this->w[nid]);
}
@@ -1562,6 +1570,7 @@ int
azalia_codec_disconnect_stream(codec_t *this, int dir)
{
const convgroup_t *group;
+ uint32_t v;
int i;
nid_t nid;
@@ -1573,6 +1582,12 @@ azalia_codec_disconnect_stream(codec_t *this, int dir)
nid = group->conv[i];
this->comresp(this, nid, CORB_SET_CONVERTER_STREAM_CHANNEL,
0, NULL); /* stream#0 */
+ if (this->w[nid].widgetcap & COP_AWCAP_DIGITAL) {
+ /* disable S/PDIF */
+ this->comresp(this, nid, CORB_GET_DIGITAL_CONTROL, 0, &v);
+ v = (v & ~CORB_DCC_DIGEN) & 0xff;
+ this->comresp(this, nid, CORB_SET_DIGITAL_CONTROL_L, v, NULL);
+ }
}
return 0;
}
diff --git a/sys/dev/pci/azalia.h b/sys/dev/pci/azalia.h
index b6d466daad7..243975d876b 100644
--- a/sys/dev/pci/azalia.h
+++ b/sys/dev/pci/azalia.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: azalia.h,v 1.16 2008/10/16 02:13:12 jakemsr Exp $ */
+/* $OpenBSD: azalia.h,v 1.17 2008/10/16 19:16:58 jakemsr Exp $ */
/* $NetBSD: azalia.h,v 1.6 2006/01/16 14:15:26 kent Exp $ */
/*-
@@ -312,9 +312,18 @@
#define CORB_AGM_OUTPUT 0x8000
#define CORB_GET_CONVERTER_FORMAT 0xa00
#define CORB_SET_CONVERTER_FORMAT 0x200
-#define CORB_GET_DIGITAL_CONVERTER_CONTROL 0xf0d
-#define CORB_SET_DIGITAL_CONVERTER_CONTROL_L 0x70d
-#define CORB_SET_DIGITAL_CONVERTER_CONTROL_H 0x70e
+#define CORB_GET_DIGITAL_CONTROL 0xf0d
+#define CORB_SET_DIGITAL_CONTROL_L 0x70d
+#define CORB_SET_DIGITAL_CONTROL_H 0x70e
+#define CORB_DCC_DIGEN 0x01
+#define CORB_DCC_V 0x02
+#define CORB_DCC_VCFG 0x04
+#define CORB_DCC_PRE 0x08
+#define CORB_DCC_COPY 0x10
+#define CORB_DCC_NAUDIO 0x20
+#define CORB_DCC_PRO 0x40
+#define CORB_DCC_L 0x80
+#define CORB_DCC_CC(x) ((x >> 8) & 0x7f)
#define CORB_GET_POWER_STATE 0xf05
#define CORB_SET_POWER_STATE 0x705
#define CORB_PS_D0 0x0
@@ -546,7 +555,9 @@ typedef struct {
#define MI_TARGET_DAC 0x104
#define MI_TARGET_ADC 0x105
#define MI_TARGET_VOLUME 0x106
-#define MI_TARGET_EAPD 0x107
+#define MI_TARGET_SPDIF 0x107
+#define MI_TARGET_SPDIF_CC 0x108
+#define MI_TARGET_EAPD 0x109
} mixer_item_t;
#define VALID_WIDGET_NID(nid, codec) (nid == (codec)->audiofunc || \
diff --git a/sys/dev/pci/azalia_codec.c b/sys/dev/pci/azalia_codec.c
index 000c3edbac8..bf9de9d7998 100644
--- a/sys/dev/pci/azalia_codec.c
+++ b/sys/dev/pci/azalia_codec.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: azalia_codec.c,v 1.50 2008/10/16 02:13:12 jakemsr Exp $ */
+/* $OpenBSD: azalia_codec.c,v 1.51 2008/10/16 19:16:58 jakemsr Exp $ */
/* $NetBSD: azalia_codec.c,v 1.8 2006/05/10 11:17:27 kent Exp $ */
/*-
@@ -68,7 +68,7 @@ int azalia_generic_mixer_delete(codec_t *);
int azalia_generic_mixer_ensure_capacity(codec_t *, size_t);
int azalia_generic_mixer_get(const codec_t *, nid_t, int, mixer_ctrl_t *);
int azalia_generic_mixer_set(codec_t *, nid_t, int, const mixer_ctrl_t *);
-int azalia_generic_mixer_pinctrl(codec_t *, nid_t, uint32_t);
+int azalia_generic_mixer_pinctrl(codec_t *, nid_t, uint32_t);
u_char azalia_generic_mixer_from_device_value
(const codec_t *, nid_t, int, uint32_t );
uint32_t azalia_generic_mixer_to_device_value
@@ -1013,6 +1013,22 @@ azalia_generic_mixer_get(const codec_t *this, nid_t nid, int target, mixer_ctrl_
mc->un.value.num_channels = 1;
}
+ /* S/PDIF */
+ else if (target == MI_TARGET_SPDIF) {
+ err = this->comresp(this, nid, CORB_GET_DIGITAL_CONTROL,
+ 0, &result);
+ if (err)
+ return err;
+ mc->un.mask = result & 0xff & ~(CORB_DCC_DIGEN | CORB_DCC_NAUDIO);
+ } else if (target == MI_TARGET_SPDIF_CC) {
+ err = this->comresp(this, nid, CORB_GET_DIGITAL_CONTROL,
+ 0, &result);
+ if (err)
+ return err;
+ mc->un.value.num_channels = 1;
+ mc->un.value.level[0] = CORB_DCC_CC(result);
+ }
+
/* EAPD */
else if (target == MI_TARGET_EAPD) {
err = this->comresp(this, nid,
@@ -1277,6 +1293,27 @@ azalia_generic_mixer_set(codec_t *this, nid_t nid, int target, const mixer_ctrl_
return err;
}
+ /* S/PDIF */
+ else if (target == MI_TARGET_SPDIF) {
+ err = this->comresp(this, nid, CORB_GET_DIGITAL_CONTROL,
+ 0, &result);
+ result &= CORB_DCC_DIGEN | CORB_DCC_NAUDIO;
+ result |= mc->un.mask & 0xff & ~CORB_DCC_DIGEN;
+ err = this->comresp(this, nid, CORB_SET_DIGITAL_CONTROL_L,
+ result, NULL);
+ if (err)
+ return err;
+ } else if (target == MI_TARGET_SPDIF_CC) {
+ if (mc->un.value.num_channels != 1)
+ return EINVAL;
+ if (mc->un.value.level[0] > 127)
+ return EINVAL;
+ err = this->comresp(this, nid, CORB_SET_DIGITAL_CONTROL_H,
+ mc->un.value.level[0], NULL);
+ if (err)
+ return err;
+ }
+
/* EAPD */
else if (target == MI_TARGET_EAPD) {
if (mc->un.ord >= 2)
@@ -1295,7 +1332,7 @@ azalia_generic_mixer_set(codec_t *this, nid_t nid, int target, const mixer_ctrl_
CORB_SET_EAPD_BTL_ENABLE, result, &result);
if (err)
return err;
- }
+ }
else {
printf("%s: internal error in %s: target=%x\n",