diff options
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/pci/azalia.c | 19 | ||||
-rw-r--r-- | sys/dev/pci/azalia.h | 21 | ||||
-rw-r--r-- | sys/dev/pci/azalia_codec.c | 43 |
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", |