diff options
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/pci/azalia.c | 8 | ||||
-rw-r--r-- | sys/dev/pci/azalia.h | 4 | ||||
-rw-r--r-- | sys/dev/pci/azalia_codec.c | 107 |
3 files changed, 79 insertions, 40 deletions
diff --git a/sys/dev/pci/azalia.c b/sys/dev/pci/azalia.c index 5eb11808bcf..dcde9e2ef96 100644 --- a/sys/dev/pci/azalia.c +++ b/sys/dev/pci/azalia.c @@ -1,4 +1,4 @@ -/* $OpenBSD: azalia.c,v 1.138 2009/06/09 05:05:48 jakemsr Exp $ */ +/* $OpenBSD: azalia.c,v 1.139 2009/06/09 05:16:42 jakemsr Exp $ */ /* $NetBSD: azalia.c,v 1.20 2006/05/07 08:31:44 kent Exp $ */ /*- @@ -2544,12 +2544,17 @@ azalia_widget_init(widget_t *this, const codec_t *codec, nid_t nid) } /* amplifier information */ + /* XXX (ab)use bits 24-30 to store the "control offset", which is + * the number of steps, starting at 0, that have no effect. these + * bits are reserved in HDA 1.0. + */ if (this->widgetcap & COP_AWCAP_INAMP) { if (this->widgetcap & COP_AWCAP_AMPOV) azalia_comresp(codec, nid, CORB_GET_PARAMETER, COP_INPUT_AMPCAP, &this->inamp_cap); else this->inamp_cap = codec->w[codec->audiofunc].inamp_cap; + this->inamp_cap &= ~(0x7f << 24); } if (this->widgetcap & COP_AWCAP_OUTAMP) { if (this->widgetcap & COP_AWCAP_AMPOV) @@ -2557,6 +2562,7 @@ azalia_widget_init(widget_t *this, const codec_t *codec, nid_t nid) COP_OUTPUT_AMPCAP, &this->outamp_cap); else this->outamp_cap = codec->w[codec->audiofunc].outamp_cap; + this->outamp_cap &= ~(0x7f << 24); } return 0; } diff --git a/sys/dev/pci/azalia.h b/sys/dev/pci/azalia.h index 087292df225..f423108b9e2 100644 --- a/sys/dev/pci/azalia.h +++ b/sys/dev/pci/azalia.h @@ -1,4 +1,4 @@ -/* $OpenBSD: azalia.h,v 1.51 2009/06/09 05:05:48 jakemsr Exp $ */ +/* $OpenBSD: azalia.h,v 1.52 2009/06/09 05:16:42 jakemsr Exp $ */ /* $NetBSD: azalia.h,v 1.6 2006/01/16 14:15:26 kent Exp $ */ /*- @@ -263,6 +263,7 @@ #define COP_AMPCAP_OFFSET(x) (x & 0x0000007f) #define COP_AMPCAP_NUMSTEPS(x) ((x >> 8) & 0x7f) #define COP_AMPCAP_STEPSIZE(x) ((x >> 16) & 0x7f) +#define COP_AMPCAP_CTLOFF(x) ((x >> 24) & 0x7f) #define COP_AMPCAP_MUTE 0x80000000 #define COP_CONNECTION_LIST_LENGTH 0x0e #define COP_CLL_LONG 0x00000080 @@ -506,6 +507,7 @@ #define AZ_QRK_WID_CDIN_1C 0x00001000 #define AZ_QRK_WID_BEEP_1D 0x00002000 #define AZ_QRK_WID_OVREF50 0x00004000 +#define AZ_QRK_WID_AD1981_OAMP 0x00008000 /* memory-mapped types */ typedef struct { diff --git a/sys/dev/pci/azalia_codec.c b/sys/dev/pci/azalia_codec.c index c42378c9d66..e8af91f440b 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.131 2009/06/09 05:05:48 jakemsr Exp $ */ +/* $OpenBSD: azalia_codec.c,v 1.132 2009/06/09 05:16:42 jakemsr Exp $ */ /* $NetBSD: azalia_codec.c,v 1.8 2006/05/10 11:17:27 kent Exp $ */ /*- @@ -46,13 +46,12 @@ int azalia_add_convgroup(codec_t *, convgroupset_t *, int azalia_mixer_fix_indexes(codec_t *); int azalia_mixer_default(codec_t *); int azalia_mixer_ensure_capacity(codec_t *, size_t); -u_char azalia_mixer_from_device_value - (const codec_t *, nid_t, int, uint32_t ); -uint32_t azalia_mixer_to_device_value - (const codec_t *, nid_t, int, u_char); +u_char azalia_mixer_from_device_value(const codec_t *, nid_t, int, uint32_t ); +uint32_t azalia_mixer_to_device_value(const codec_t *, nid_t, int, u_char); void azalia_devinfo_offon(mixer_devinfo_t *); void azalia_pin_config_ov(widget_t *, int, int); +void azalia_ampcap_ov(widget_t *, int, int, int, int, int, int); int azalia_gpio_unmute(codec_t *, int); @@ -198,6 +197,7 @@ azalia_codec_init_vtbl(codec_t *this) break; case 0x11d41981: this->name = "Analog Devices AD1981HD"; + this->qrks |= AZ_QRK_WID_AD1981_OAMP; break; case 0x11d41983: this->name = "Analog Devices AD1983"; @@ -1670,15 +1670,14 @@ azalia_mixer_get(const codec_t *this, nid_t nid, int target, } int -azalia_mixer_set(codec_t *this, nid_t nid, int target, - const mixer_ctrl_t *mc) +azalia_mixer_set(codec_t *this, nid_t nid, int target, const mixer_ctrl_t *mc) { uint32_t result, value; int i, err; /* inamp mute */ if (IS_MI_TARGET_INAMP(target) && mc->type == AUDIO_MIXER_ENUM) { - /* We have to set stereo mute separately to keep each gain value. */ + /* set stereo mute separately to keep each gain value */ err = azalia_comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE, CORB_GAGM_INPUT | CORB_GAGM_LEFT | MI_TARGET_INAMP(target), &result); @@ -2189,42 +2188,51 @@ u_char azalia_mixer_from_device_value(const codec_t *this, nid_t nid, int target, uint32_t dv) { - uint32_t dmax; - - if (IS_MI_TARGET_INAMP(target)) - dmax = COP_AMPCAP_NUMSTEPS(this->w[nid].inamp_cap); - else if (target == MI_TARGET_OUTAMP) - dmax = COP_AMPCAP_NUMSTEPS(this->w[nid].outamp_cap); - else { - printf("unknown target: %d\n", target); - dmax = 255; - } - if (dv <= 0 || dmax == 0) - return AUDIO_MIN_GAIN; - if (dv >= dmax) - return AUDIO_MAX_GAIN - AUDIO_MAX_GAIN % dmax; - return dv * (AUDIO_MAX_GAIN - AUDIO_MAX_GAIN % dmax) / dmax; + uint32_t steps; + int max_gain, ctloff; + + if (IS_MI_TARGET_INAMP(target)) { + steps = COP_AMPCAP_NUMSTEPS(this->w[nid].inamp_cap); + ctloff = COP_AMPCAP_CTLOFF(this->w[nid].inamp_cap); + } else if (target == MI_TARGET_OUTAMP) { + steps = COP_AMPCAP_NUMSTEPS(this->w[nid].outamp_cap); + ctloff = COP_AMPCAP_CTLOFF(this->w[nid].outamp_cap); + } else { + printf("%s: unknown target: %d\n", __func__, target); + steps = 255; + } + dv -= ctloff; + if (dv <= 0 || steps == 0) + return(AUDIO_MIN_GAIN); + max_gain = AUDIO_MAX_GAIN - AUDIO_MAX_GAIN % steps; + if (dv >= steps) + return(max_gain); + return(dv * max_gain / steps); } uint32_t azalia_mixer_to_device_value(const codec_t *this, nid_t nid, int target, u_char uv) { - uint32_t dmax; - - if (IS_MI_TARGET_INAMP(target)) - dmax = COP_AMPCAP_NUMSTEPS(this->w[nid].inamp_cap); - else if (target == MI_TARGET_OUTAMP) - dmax = COP_AMPCAP_NUMSTEPS(this->w[nid].outamp_cap); - else { - printf("unknown target: %d\n", target); - dmax = 255; - } - if (uv <= AUDIO_MIN_GAIN || dmax == 0) - return 0; - if (uv >= AUDIO_MAX_GAIN - AUDIO_MAX_GAIN % dmax) - return dmax; - return uv * dmax / (AUDIO_MAX_GAIN - AUDIO_MAX_GAIN % dmax); + uint32_t steps; + int max_gain, ctloff; + + if (IS_MI_TARGET_INAMP(target)) { + steps = COP_AMPCAP_NUMSTEPS(this->w[nid].inamp_cap); + ctloff = COP_AMPCAP_CTLOFF(this->w[nid].inamp_cap); + } else if (target == MI_TARGET_OUTAMP) { + steps = COP_AMPCAP_NUMSTEPS(this->w[nid].outamp_cap); + ctloff = COP_AMPCAP_CTLOFF(this->w[nid].outamp_cap); + } else { + printf("%s: unknown target: %d\n", __func__, target); + steps = 255; + } + if (uv <= AUDIO_MIN_GAIN || steps == 0) + return(ctloff); + max_gain = AUDIO_MAX_GAIN - AUDIO_MAX_GAIN % steps; + if (uv >= max_gain) + return(steps + ctloff); + return(uv * steps / max_gain + ctloff); } int @@ -2249,6 +2257,23 @@ azalia_gpio_unmute(codec_t *this, int pin) } void +azalia_ampcap_ov(widget_t *w, int type, int offset, int steps, int size, + int ctloff, int mute) +{ + uint32_t cap; + + cap = (offset & 0x7f) | ((steps & 0x7f) << 8) | + ((size & 0x7f) << 16) | ((ctloff & 0x7f) << 24) | + (mute ? COP_AMPCAP_MUTE : 0); + + if (type == COP_OUTPUT_AMPCAP) { + w->outamp_cap = cap; + } else if (type == COP_INPUT_AMPCAP) { + w->inamp_cap = cap; + } +} + +void azalia_pin_config_ov(widget_t *w, int mask, int val) { int bits, offset; @@ -2314,5 +2339,11 @@ azalia_codec_widget_quirks(codec_t *this, nid_t nid) w->enable = 1; } + if ((this->qrks & AZ_QRK_WID_AD1981_OAMP) && + ((nid == 0x05) || (nid == 0x06) || (nid == 0x07) || + (nid == 0x09) || (nid == 0x18))) { + azalia_ampcap_ov(w, COP_OUTPUT_AMPCAP, 31, 33, 6, 30, 1); + } + return(0); } |