summaryrefslogtreecommitdiff
path: root/sys/dev/pci/azalia_codec.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/pci/azalia_codec.c')
-rw-r--r--sys/dev/pci/azalia_codec.c108
1 files changed, 104 insertions, 4 deletions
diff --git a/sys/dev/pci/azalia_codec.c b/sys/dev/pci/azalia_codec.c
index 3b871931171..43937c718c7 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.98 2008/12/28 23:15:14 jakemsr Exp $ */
+/* $OpenBSD: azalia_codec.c,v 1.99 2008/12/31 13:13:39 jakemsr Exp $ */
/* $NetBSD: azalia_codec.c,v 1.8 2006/05/10 11:17:27 kent Exp $ */
/*-
@@ -66,9 +66,11 @@ int azalia_generic_codec_init_dacgroup(codec_t *);
int azalia_generic_codec_fnode(codec_t *, nid_t, int, int);
int azalia_generic_codec_add_convgroup(codec_t *, convgroupset_t *,
uint32_t, uint32_t);
+
+int azalia_generic_unsol(codec_t *, int);
+
int azalia_generic_mixer_init(codec_t *);
int azalia_generic_mixer_autoinit(codec_t *);
-
int azalia_generic_mixer_fix_indexes(codec_t *);
int azalia_generic_mixer_default(codec_t *);
int azalia_generic_mixer_create_virtual(codec_t *, int, int);
@@ -109,7 +111,7 @@ azalia_codec_init_vtbl(codec_t *this)
this->mixer_delete = azalia_generic_mixer_delete;
this->set_port = azalia_generic_set_port;
this->get_port = azalia_generic_get_port;
- this->unsol_event = NULL;
+ this->unsol_event = azalia_generic_unsol;
switch (this->vid) {
case 0x10ec0260:
this->name = "Realtek ALC260";
@@ -441,6 +443,42 @@ azalia_generic_codec_fnode(codec_t *this, nid_t node, int index, int depth)
return -1;
}
+int
+azalia_generic_unsol(codec_t *this, int tag)
+{
+ mixer_ctrl_t mc;
+ uint32_t result;
+ int i, err;
+
+ tag = CORB_UNSOL_TAG(tag);
+ switch (tag) {
+ case AZ_TAG_SPKR:
+ mc.type = AUDIO_MIXER_ENUM;
+ mc.un.ord = 0;
+ for (i = 0; mc.un.ord == 0 && i < this->nsense_pins; i++) {
+ if (!(this->spkr_muters & (1 <<i)))
+ continue;
+ err = this->comresp(this, this->sense_pins[i],
+ CORB_GET_PIN_WIDGET_CONTROL, 0, &result);
+ if (err || !(result & CORB_PWC_OUTPUT))
+ continue;
+ err = this->comresp(this, this->sense_pins[i],
+ CORB_GET_PIN_SENSE, 0, &result);
+ if (!err && (result & CORB_PS_PRESENCE))
+ mc.un.ord = 1;
+ }
+ azalia_generic_mixer_set(this, this->speaker,
+ MI_TARGET_OUTAMP, &mc);
+ break;
+ default:
+ DPRINTF(("%s: unknown tag %d\n", __func__, tag));
+ break;
+ }
+
+ return 0;
+}
+
+
/* ----------------------------------------------------------------
* Generic mixer functions
* ---------------------------------------------------------------- */
@@ -455,6 +493,7 @@ azalia_generic_mixer_init(codec_t *this)
* mixer "mixer%2.2x"
* selector "sel%2.2x"
*/
+ const widget_t *w, *ww;
mixer_item_t *m;
int err, i, j, k;
@@ -510,7 +549,6 @@ azalia_generic_mixer_init(codec_t *this)
m->nid = i
FOR_EACH_WIDGET(this, i) {
- const widget_t *w;
w = &this->w[i];
if (!w->enable)
@@ -763,6 +801,35 @@ azalia_generic_mixer_init(codec_t *this)
this->nmixers++;
}
+ /* spkr mute by jack sense */
+ w = &this->w[this->speaker];
+ if (this->nsense_pins > 0 && this->speaker != -1 &&
+ (w->widgetcap & COP_AWCAP_OUTAMP) &&
+ (w->outamp_cap & COP_AMPCAP_MUTE)) {
+ MIXER_REG_PROLOG;
+ m->nid = w->nid;
+ snprintf(d->label.name, sizeof(d->label.name),
+ "%s_muters", w->name);
+ m->target = MI_TARGET_SENSESET;
+ d->type = AUDIO_MIXER_SET;
+ d->mixer_class = AZ_CLASS_OUTPUT;
+ this->spkr_muters = 0;
+ for (i = 0, j = 0; i < this->nsense_pins; i++) {
+ ww = &this->w[this->sense_pins[i]];
+ if (!(w->d.pin.cap & COP_PINCAP_OUTPUT))
+ continue;
+ if (!(w->widgetcap & COP_AWCAP_UNSOL))
+ continue;
+ d->un.s.member[j].mask = 1 << i;
+ this->spkr_muters |= (1 << i);
+ strlcpy(d->un.s.member[j++].label.name, ww->name,
+ MAX_AUDIO_DEV_LEN);
+ }
+ d->un.s.num_mem = j;
+ if (j != 0)
+ this->nmixers++;
+ }
+
/* if the codec has multiple DAC groups, create "inputs.usingdac" */
if (this->dacs.ngroups > 1) {
MIXER_REG_PROLOG;
@@ -933,6 +1000,17 @@ azalia_generic_mixer_default(codec_t *this)
azalia_generic_mixer_set(this, m->nid, m->target, &mc);
}
+ /* turn on jack sense unsolicited responses */
+ for (i = 0; i < this->nsense_pins; i++) {
+ if (this->spkr_muters & (1 << i)) {
+ this->comresp(this, this->sense_pins[i],
+ CORB_SET_UNSOLICITED_RESPONSE,
+ CORB_UNSOL_ENABLE | AZ_TAG_SPKR, NULL);
+ }
+ }
+ if (this->spkr_muters != 0 && this->unsol_event != NULL)
+ this->unsol_event(this, AZ_TAG_SPKR);
+
return 0;
}
@@ -1259,6 +1337,16 @@ azalia_generic_mixer_get(const codec_t *this, nid_t nid, int target,
}
}
+ else if (target == MI_TARGET_SENSESET && mc->type == AUDIO_MIXER_SET) {
+
+ if (nid == this->speaker) {
+ mc->un.mask = this->spkr_muters;
+ } else {
+ DPRINTF(("%s: invalid senseset nid\n"));
+ return EINVAL;
+ }
+ }
+
else {
printf("%s: internal error in %s: target=%x\n",
XNAME(this), __func__, target);
@@ -1604,6 +1692,18 @@ azalia_generic_mixer_set(codec_t *this, nid_t nid, int target,
}
}
+ else if (target == MI_TARGET_SENSESET && mc->type == AUDIO_MIXER_SET) {
+
+ if (nid == this->speaker) {
+ this->spkr_muters = mc->un.mask;
+ if (this->unsol_event != NULL)
+ this->unsol_event(this, AZ_TAG_SPKR);
+ } else {
+ DPRINTF(("%s: invalid senseset nid\n"));
+ return EINVAL;
+ }
+ }
+
else {
printf("%s: internal error in %s: target=%x\n",
XNAME(this), __func__, target);