summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/pci/azalia.c8
-rw-r--r--sys/dev/pci/azalia.h4
-rw-r--r--sys/dev/pci/azalia_codec.c107
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);
}