diff --git a/sys/dev/pci/azalia.h b/sys/dev/pci/azalia.h index b729a9948886..c0eb28703acd 100644 --- a/sys/dev/pci/azalia.h +++ b/sys/dev/pci/azalia.h @@ -1,4 +1,4 @@ -/* $NetBSD: azalia.h,v 1.13 2006/06/25 13:41:58 kent Exp $ */ +/* $NetBSD: azalia.h,v 1.14 2006/07/21 14:40:12 kent Exp $ */ /*- * Copyright (c) 2005 The NetBSD Foundation, Inc. @@ -356,6 +356,9 @@ #define CORB_PS_RIGHT 0x1 #define CORB_GET_EAPD_BTL_ENABLE 0xf0c #define CORB_SET_EAPD_BTL_ENABLE 0x70c +#define CORB_EAPD_BTL 0x01 +#define CORB_EAPD_EAPD 0x02 +#define CORB_EAPD_LRSWAP 0x04 #define CORB_GET_GPI_DATA 0xf10 #define CORB_SET_GPI_DATA 0x710 #define CORB_GET_GPI_WAKE_ENABLE_MASK 0xf11 @@ -523,6 +526,9 @@ typedef struct { #define MI_TARGET_VOLUME 0x106 #define MI_TARGET_SPDIF 0x107 #define MI_TARGET_SPDIF_CC 0x108 +#define MI_TARGET_EAPD 0x109 +#define MI_TARGET_BALANCE 0x10a +#define MI_TARGET_LRSWAP 0x10b } 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 571ca1d7f24e..e0972ed46289 100644 --- a/sys/dev/pci/azalia_codec.c +++ b/sys/dev/pci/azalia_codec.c @@ -1,4 +1,4 @@ -/* $NetBSD: azalia_codec.c,v 1.22 2006/07/19 02:40:18 kent Exp $ */ +/* $NetBSD: azalia_codec.c,v 1.23 2006/07/21 14:40:12 kent Exp $ */ /*- * Copyright (c) 2005 The NetBSD Foundation, Inc. @@ -37,7 +37,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: azalia_codec.c,v 1.22 2006/07/19 02:40:18 kent Exp $"); +__KERNEL_RCSID(0, "$NetBSD: azalia_codec.c,v 1.23 2006/07/21 14:40:12 kent Exp $"); #include #include @@ -694,6 +694,72 @@ generic_mixer_init(codec_t *this) this->nmixers++; } + if (w->type == COP_AWTYPE_PIN_COMPLEX && + w->d.pin.cap & COP_PINCAP_EAPD) { + MIXER_REG_PROLOG; + DPRINTF(("%s: eapd %s\n", __func__, w->name)); + snprintf(d->label.name, sizeof(d->label.name), + "%s.eapd", w->name); + d->type = AUDIO_MIXER_ENUM; + d->mixer_class = AZ_CLASS_OUTPUT; + m->target = MI_TARGET_EAPD; + d->un.e.num_mem = 2; + d->un.e.member[0].ord = 0; + strlcpy(d->un.e.member[0].label.name, AudioNoff, + MAX_AUDIO_DEV_LEN); + d->un.e.member[1].ord = 1; + strlcpy(d->un.e.member[1].label.name, AudioNon, + MAX_AUDIO_DEV_LEN); + this->nmixers++; + } + + if (w->type == COP_AWTYPE_PIN_COMPLEX && + w->d.pin.cap & COP_PINCAP_BALANCE) { + MIXER_REG_PROLOG; + DPRINTF(("%s: balance %s\n", __func__, w->name)); + snprintf(d->label.name, sizeof(d->label.name), + "%s.balance", w->name); + d->type = AUDIO_MIXER_ENUM; + if (w->type == COP_AWTYPE_PIN_COMPLEX) + d->mixer_class = AZ_CLASS_OUTPUT; + else if (w->type == COP_AWTYPE_AUDIO_INPUT) + d->mixer_class = AZ_CLASS_RECORD; + else + d->mixer_class = AZ_CLASS_INPUT; + m->target = MI_TARGET_BALANCE; + d->un.e.num_mem = 2; + d->un.e.member[0].ord = 0; + strlcpy(d->un.e.member[0].label.name, AudioNoff, + MAX_AUDIO_DEV_LEN); + d->un.e.member[1].ord = 1; + strlcpy(d->un.e.member[1].label.name, AudioNon, + MAX_AUDIO_DEV_LEN); + this->nmixers++; + } + + if (w->widgetcap & COP_AWCAP_LRSWAP) { + MIXER_REG_PROLOG; + DPRINTF(("%s: lrswap %s\n", __func__, w->name)); + snprintf(d->label.name, sizeof(d->label.name), + "%s.lrswap", w->name); + d->type = AUDIO_MIXER_ENUM; + if (w->type == COP_AWTYPE_PIN_COMPLEX) + d->mixer_class = AZ_CLASS_OUTPUT; + else if (w->type == COP_AWTYPE_AUDIO_INPUT) + d->mixer_class = AZ_CLASS_RECORD; + else + d->mixer_class = AZ_CLASS_INPUT; + m->target = MI_TARGET_LRSWAP; + d->un.e.num_mem = 2; + d->un.e.member[0].ord = 0; + strlcpy(d->un.e.member[0].label.name, AudioNoff, + MAX_AUDIO_DEV_LEN); + d->un.e.member[1].ord = 1; + strlcpy(d->un.e.member[1].label.name, AudioNon, + MAX_AUDIO_DEV_LEN); + this->nmixers++; + } + /* volume knob */ if (w->type == COP_AWTYPE_VOLUME_KNOB && w->d.volume.cap & COP_VKCAP_DELTA) { @@ -1048,6 +1114,33 @@ generic_mixer_get(const codec_t *this, nid_t nid, int target, mixer_ctrl_t *mc) mc->un.value.level[0] = CORB_DCC_CC(result); } + /* EAPD */ + else if (target == MI_TARGET_EAPD) { + err = this->comresp(this, nid, + CORB_GET_EAPD_BTL_ENABLE, 0, &result); + if (err) + return err; + mc->un.ord = result & CORB_EAPD_EAPD ? 1 : 0; + } + + /* Balanced I/O */ + else if (target == MI_TARGET_BALANCE) { + err = this->comresp(this, nid, + CORB_GET_EAPD_BTL_ENABLE, 0, &result); + if (err) + return err; + mc->un.ord = result & CORB_EAPD_BTL ? 1 : 0; + } + + /* LR-Swap */ + else if (target == MI_TARGET_LRSWAP) { + err = this->comresp(this, nid, + CORB_GET_EAPD_BTL_ENABLE, 0, &result); + if (err) + return err; + mc->un.ord = result & CORB_EAPD_LRSWAP ? 1 : 0; + } + else { aprint_error("%s: internal error in %s: target=%x\n", XNAME(this), __func__, target); @@ -1324,6 +1417,66 @@ generic_mixer_set(codec_t *this, nid_t nid, int target, const mixer_ctrl_t *mc) return err; } + /* EAPD */ + else if (target == MI_TARGET_EAPD) { + if (mc->un.ord >= 2) + return EINVAL; + err = this->comresp(this, nid, + CORB_GET_EAPD_BTL_ENABLE, 0, &result); + if (err) + return err; + result &= 0xff; + if (mc->un.ord == 0) { + result &= ~CORB_EAPD_EAPD; + } else { + result |= CORB_EAPD_EAPD; + } + err = this->comresp(this, nid, + CORB_SET_EAPD_BTL_ENABLE, result, &result); + if (err) + return err; + } + + /* Balanced I/O */ + else if (target == MI_TARGET_BALANCE) { + if (mc->un.ord >= 2) + return EINVAL; + err = this->comresp(this, nid, + CORB_GET_EAPD_BTL_ENABLE, 0, &result); + if (err) + return err; + result &= 0xff; + if (mc->un.ord == 0) { + result &= ~CORB_EAPD_BTL; + } else { + result |= CORB_EAPD_BTL; + } + err = this->comresp(this, nid, + CORB_SET_EAPD_BTL_ENABLE, result, &result); + if (err) + return err; + } + + /* LR-Swap */ + else if (target == MI_TARGET_LRSWAP) { + if (mc->un.ord >= 2) + return EINVAL; + err = this->comresp(this, nid, + CORB_GET_EAPD_BTL_ENABLE, 0, &result); + if (err) + return err; + result &= 0xff; + if (mc->un.ord == 0) { + result &= ~CORB_EAPD_LRSWAP; + } else { + result |= CORB_EAPD_LRSWAP; + } + err = this->comresp(this, nid, + CORB_SET_EAPD_BTL_ENABLE, result, &result); + if (err) + return err; + } + else { aprint_error("%s: internal error in %s: target=%x\n", XNAME(this), __func__, target);