diff options
-rw-r--r-- | sys/dev/pci/azalia.c | 20 | ||||
-rw-r--r-- | sys/dev/pci/azalia.h | 5 | ||||
-rw-r--r-- | sys/dev/pci/azalia_codec.c | 118 |
3 files changed, 84 insertions, 59 deletions
diff --git a/sys/dev/pci/azalia.c b/sys/dev/pci/azalia.c index 15c5abfb40f..210c371321e 100644 --- a/sys/dev/pci/azalia.c +++ b/sys/dev/pci/azalia.c @@ -1,4 +1,4 @@ -/* $OpenBSD: azalia.c,v 1.107 2009/01/02 22:32:25 jakemsr Exp $ */ +/* $OpenBSD: azalia.c,v 1.108 2009/01/03 19:17:45 jakemsr Exp $ */ /* $NetBSD: azalia.c,v 1.20 2006/05/07 08:31:44 kent Exp $ */ /*- @@ -1449,14 +1449,16 @@ azalia_codec_init_volgroups(codec_t *this) } this->playvols.master = this->audiofunc; - FOR_EACH_WIDGET(this, i) { - w = &this->w[i]; - if (w->type != COP_AWTYPE_VOLUME_KNOB) - continue; - if (!(w->widgetcap & COP_AWCAP_UNSOL)) - continue; - this->playvols.master = w->nid; - break; + if (this->playvols.nslaves > 0) { + FOR_EACH_WIDGET(this, i) { + w = &this->w[i]; + if (w->type != COP_AWTYPE_VOLUME_KNOB) + continue; + if (!COP_VKCAP_NUMSTEPS(w->d.volume.cap)) + continue; + this->playvols.master = w->nid; + break; + } } j = 0; diff --git a/sys/dev/pci/azalia.h b/sys/dev/pci/azalia.h index bc4036f2498..bdb8c02e29f 100644 --- a/sys/dev/pci/azalia.h +++ b/sys/dev/pci/azalia.h @@ -1,4 +1,4 @@ -/* $OpenBSD: azalia.h,v 1.36 2009/01/02 22:32:25 jakemsr Exp $ */ +/* $OpenBSD: azalia.h,v 1.37 2009/01/03 19:17:45 jakemsr Exp $ */ /* $NetBSD: azalia.h,v 1.6 2006/01/16 14:15:26 kent Exp $ */ /*- @@ -490,6 +490,7 @@ #define AZ_MAX_VOL_SLAVES 16 #define AZ_TAG_SPKR 0x01 +#define AZ_TAG_PLAYVOL 0x02 #define AZ_CLASS_INPUT 0 #define AZ_CLASS_OUTPUT 1 @@ -604,6 +605,8 @@ typedef struct { int vol_l; int vol_r; int mute; + int hw_step; + int hw_nsteps; nid_t slaves[AZ_MAX_VOL_SLAVES]; int nslaves; int mask; diff --git a/sys/dev/pci/azalia_codec.c b/sys/dev/pci/azalia_codec.c index 10c5d38cfc2..22c38ce6633 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.106 2009/01/02 22:32:25 jakemsr Exp $ */ +/* $OpenBSD: azalia_codec.c,v 1.107 2009/01/03 19:17:45 jakemsr Exp $ */ /* $NetBSD: azalia_codec.c,v 1.8 2006/05/10 11:17:27 kent Exp $ */ /*- @@ -439,7 +439,7 @@ azalia_generic_unsol(codec_t *this, int tag) { mixer_ctrl_t mc; uint32_t result; - int i, err; + int i, err, vol, vol2; tag = CORB_UNSOL_TAG(tag); switch (tag) { @@ -461,6 +461,41 @@ azalia_generic_unsol(codec_t *this, int tag) azalia_generic_mixer_set(this, this->speaker, MI_TARGET_OUTAMP, &mc); break; + + case AZ_TAG_PLAYVOL: + if (this->playvols.master == this->audiofunc) + return EINVAL; + err = this->comresp(this, this->playvols.master, + CORB_GET_VOLUME_KNOB, 0, &result); + if (err) + return err; + + vol = CORB_VKNOB_VOLUME(result) - this->playvols.hw_step; + vol2 = vol * (AUDIO_MAX_GAIN / this->playvols.hw_nsteps); + this->playvols.hw_step = CORB_VKNOB_VOLUME(result); + + vol = vol2 + this->playvols.vol_l; + if (vol < 0) + vol = 0; + else if (vol > AUDIO_MAX_GAIN) + vol = AUDIO_MAX_GAIN; + this->playvols.vol_l = vol; + + vol = vol2 + this->playvols.vol_r; + if (vol < 0) + vol = 0; + else if (vol > AUDIO_MAX_GAIN) + vol = AUDIO_MAX_GAIN; + this->playvols.vol_r = vol; + + mc.type = AUDIO_MIXER_VALUE; + mc.un.value.num_channels = 2; + mc.un.value.level[0] = this->playvols.vol_l; + mc.un.value.level[1] = this->playvols.vol_r; + azalia_generic_mixer_set(this, this->playvols.master, + MI_TARGET_PLAYVOL, &mc); + break; + default: DPRINTF(("%s: unknown tag %d\n", __func__, tag)); break; @@ -760,21 +795,6 @@ azalia_generic_mixer_init(codec_t *this) azalia_devinfo_offon(d); this->nmixers++; } - - /* volume knob */ - if (w->type == COP_AWTYPE_VOLUME_KNOB && - w->d.volume.cap & COP_VKCAP_DELTA) { - MIXER_REG_PROLOG; - strlcpy(d->label.name, w->name, sizeof(d->label.name)); - d->type = AUDIO_MIXER_VALUE; - d->mixer_class = AZ_CLASS_OUTPUT; - m->target = MI_TARGET_VOLUME; - d->un.v.num_channels = 1; - d->un.v.units.name[0] = 0; - d->un.v.delta = - MIXER_DELTA(COP_VKCAP_NUMSTEPS(w->d.volume.cap)); - this->nmixers++; - } } /* sense pins */ @@ -1046,7 +1066,8 @@ azalia_generic_mixer_default(codec_t *this) widget_t *w; mixer_item_t *m; mixer_ctrl_t mc; - int i, j, tgt, cap; + int i, j, tgt, cap, err; + uint32_t result; /* unmute all */ for (i = 0; i < this->nmixers; i++) { @@ -1066,8 +1087,7 @@ azalia_generic_mixer_default(codec_t *this) for (i = 0; i < this->nmixers; i++) { m = &this->mixers[i]; if (!IS_MI_TARGET_INAMP(m->target) && - m->target != MI_TARGET_OUTAMP && - m->target != MI_TARGET_VOLUME) + m->target != MI_TARGET_OUTAMP) continue; if (m->devinfo.type != AUDIO_MIXER_VALUE) continue; @@ -1076,8 +1096,7 @@ azalia_generic_mixer_default(codec_t *this) mc.type = AUDIO_MIXER_VALUE; mc.un.value.num_channels = 1; mc.un.value.level[0] = AUDIO_MAX_GAIN / 2; - if (m->target != MI_TARGET_VOLUME && - WIDGET_CHANNELS(&this->w[m->nid]) == 2) { + if (WIDGET_CHANNELS(&this->w[m->nid]) == 2) { mc.un.value.num_channels = 2; mc.un.value.level[1] = mc.un.value.level[0]; } @@ -1156,6 +1175,34 @@ azalia_generic_mixer_default(codec_t *this) } this->recvols.mute = 0; + /* volume knob */ + if (this->playvols.master != this->audiofunc) { + + w = &this->w[this->playvols.master]; + err = this->comresp(this, w->nid, CORB_GET_VOLUME_KNOB, + 0, &result); + if (err) + return err; + + /* current level */ + this->playvols.hw_step = CORB_VKNOB_VOLUME(result); + this->playvols.hw_nsteps = COP_VKCAP_NUMSTEPS(w->d.volume.cap); + + /* indirect mode */ + result &= ~(CORB_VKNOB_DIRECT); + err = this->comresp(this, w->nid, CORB_SET_VOLUME_KNOB, + result, NULL); + if (err) + return err; + + /* enable unsolicited responses */ + result = CORB_UNSOL_ENABLE | AZ_TAG_PLAYVOL; + err = this->comresp(this, w->nid, + CORB_SET_UNSOLICITED_RESPONSE, result, NULL); + if (err) + return err; + } + return 0; } @@ -1293,17 +1340,6 @@ azalia_generic_mixer_get(const codec_t *this, nid_t nid, int target, mc->un.ord = this->adcs.cur; } - /* Volume knob */ - else if (target == MI_TARGET_VOLUME) { - err = this->comresp(this, nid, CORB_GET_VOLUME_KNOB, - 0, &result); - if (err) - return err; - mc->un.value.level[0] = azalia_generic_mixer_from_device_value(this, - nid, target, CORB_VKNOB_VOLUME(result)); - mc->un.value.num_channels = 1; - } - /* S/PDIF */ else if (target == MI_TARGET_SPDIF) { err = this->comresp(this, nid, CORB_GET_DIGITAL_CONTROL, @@ -1655,18 +1691,6 @@ azalia_generic_mixer_set(codec_t *this, nid_t nid, int target, return 0; } - /* Volume knob */ - else if (target == MI_TARGET_VOLUME) { - if (mc->un.value.num_channels != 1) - return EINVAL; - value = azalia_generic_mixer_to_device_value(this, nid, target, - mc->un.value.level[0]) | CORB_VKNOB_DIRECT; - err = this->comresp(this, nid, CORB_SET_VOLUME_KNOB, - value, &result); - if (err) - return err; - } - /* S/PDIF */ else if (target == MI_TARGET_SPDIF) { err = this->comresp(this, nid, CORB_GET_DIGITAL_CONTROL, @@ -1927,8 +1951,6 @@ azalia_generic_mixer_from_device_value(const codec_t *this, nid_t nid, int targe 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 if (target == MI_TARGET_VOLUME) - dmax = COP_VKCAP_NUMSTEPS(this->w[nid].d.volume.cap); else { printf("unknown target: %d\n", target); dmax = 255; @@ -1950,8 +1972,6 @@ azalia_generic_mixer_to_device_value(const codec_t *this, nid_t nid, int 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 if (target == MI_TARGET_VOLUME) - dmax = COP_VKCAP_NUMSTEPS(this->w[nid].d.volume.cap); else { printf("unknown target: %d\n", target); dmax = 255; |