diff options
author | Jacob Meuser <jakemsr@cvs.openbsd.org> | 2008-11-19 03:44:15 +0000 |
---|---|---|
committer | Jacob Meuser <jakemsr@cvs.openbsd.org> | 2008-11-19 03:44:15 +0000 |
commit | 2e126ab14cf2f2a94f19eed4060eec69a2c9e000 (patch) | |
tree | 3659b1eb9da708eb2af3507d17e73c6a291d663c /sys | |
parent | a92bbc472ac73b5869592a795d91fd88e6cc0311 (diff) |
the jack sense automatic muting code has many problems, including
being the cause of PR5982. unfortunately, there's no easy and clean
solution to automatic muting. we can't always rely on the codec
giving us the right information. people have different preferences
as to what should be muted and what shouldn't. etc, etc.
so instead, just make the sense state of jacks that support sensing
available through the mixer interface. this allows for any possible
user configuration and supports all pins that have sense capabilities,
not just headpones. codecs that use the generic mixer configuration
(which is the plan for all codecs) and have sensing capable pins will
now get a few more read-only mixer items, such as:
outputs.hp_sense=plugged
outputs.mic_sense=unplugged
outputs.line_sense=unplugged
hopefully what they mean is self-explanatory.
based on much discussion with ratchov@ and Alexey Suslikov
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/pci/azalia.c | 115 | ||||
-rw-r--r-- | sys/dev/pci/azalia.h | 7 | ||||
-rw-r--r-- | sys/dev/pci/azalia_codec.c | 44 |
3 files changed, 59 insertions, 107 deletions
diff --git a/sys/dev/pci/azalia.c b/sys/dev/pci/azalia.c index 4d6921ed9ba..843f6940406 100644 --- a/sys/dev/pci/azalia.c +++ b/sys/dev/pci/azalia.c @@ -1,4 +1,4 @@ -/* $OpenBSD: azalia.c,v 1.72 2008/11/14 21:58:11 jakemsr Exp $ */ +/* $OpenBSD: azalia.c,v 1.73 2008/11/19 03:44:14 jakemsr Exp $ */ /* $NetBSD: azalia.c,v 1.20 2006/05/07 08:31:44 kent Exp $ */ /*- @@ -43,7 +43,6 @@ #include <sys/param.h> #include <sys/device.h> -#include <sys/timeout.h> #include <sys/malloc.h> #include <sys/systm.h> #include <uvm/uvm_param.h> @@ -171,7 +170,6 @@ typedef struct azalia_t { codec_t codecs[15]; int ncodecs; /* number of codecs */ int codecno; /* index of the using codec */ - struct timeout timeo; azalia_dma_t corb_dma; int corb_size; @@ -223,8 +221,6 @@ int azalia_free_dmamem(const azalia_t *, azalia_dma_t*); int azalia_codec_init(codec_t *); int azalia_codec_delete(codec_t *); -void azalia_codec_jack_intr(void *); -void azalia_codec_jack_handler(codec_t *); void azalia_codec_add_bits(codec_t *, int, uint32_t, int); void azalia_codec_add_format(codec_t *, int, int, int, uint32_t, int32_t); @@ -731,112 +727,12 @@ azalia_attach_intr(struct device *self) az->audiodev = audio_attach_mi(&azalia_hw_if, az, &az->dev); - /* Setup jack_intr if only there is no unsol_event handler. */ - if (az->codecs[az->codecno].unsol_event == NULL) { - timeout_set(&az->timeo, azalia_codec_jack_intr, az); - timeout_add_sec(&az->timeo, 2); - } - return; err_exit: azalia_pci_detach(self, 0); return; } -void -azalia_codec_jack_intr(void *addr) -{ - struct azalia_t *az = (struct azalia_t *)addr; - int s; - - s = splaudio(); - azalia_codec_jack_handler(&az->codecs[az->codecno]); - timeout_add_sec(&az->timeo, 2); - splx(s); -} - -void -azalia_codec_jack_handler(codec_t *this) -{ - int i, j, err, dev; - uint32_t sense, ctl, val, dir; - - FOR_EACH_WIDGET(this, i) { - const widget_t *w; - - dev = 0; - w = &this->w[i]; - - /* Find pin with conn=jack and presence capability. */ - if (w == NULL || w->type != COP_AWTYPE_PIN_COMPLEX || - (CORB_CD_PORT(w->d.pin.config)) != CORB_CD_JACK || - (!(w->d.pin.cap & COP_PINCAP_PRESENCE))) - continue; - - /* Headphones. */ - if (w->d.pin.device == CORB_CD_HEADPHONE && - (w->d.pin.cap & COP_PINCAP_HEADPHONE)) { - dev = CORB_CD_SPEAKER; /* (un)mute speakers */ - dir = CORB_PWC_OUTPUT; - } - - if (!dev) - continue; - - err = this->comresp(this, w->nid, CORB_GET_PIN_SENSE, - 0, &sense); - if (err) - break; - - err = this->comresp(this, w->nid, CORB_GET_PIN_WIDGET_CONTROL, - 0, &ctl); - if (err) - break; - - if (sense & CORB_PS_PRESENCE) - val = ctl | dir; - else - val = ctl & ~dir; - - if (val != ctl) { - ctl = val; - err = this->comresp(this, w->nid, - CORB_SET_PIN_WIDGET_CONTROL, ctl, NULL); - if (err) - break; - } - - FOR_EACH_WIDGET(this, j) { - const widget_t *w; - - w = &this->w[j]; - - /* Find suitable and connected pin for (un)mute. */ - if (w == NULL || w->type != COP_AWTYPE_PIN_COMPLEX || - (CORB_CD_PORT(w->d.pin.config)) == CORB_CD_NONE || - j == i || w->d.pin.device != dev) - continue; - - err = this->comresp(this, w->nid, - CORB_GET_PIN_WIDGET_CONTROL, 0, &ctl); - if (err) - break; - - if (sense & CORB_PS_PRESENCE) - val = ctl & ~dir; - else - val = ctl | dir; - - if (val != ctl) { - ctl = val; - err = this->comresp(this, w->nid, - CORB_SET_PIN_WIDGET_CONTROL, ctl, NULL); - if (err) - break; - } - } - } -} int azalia_init_corb(azalia_t *az) @@ -1897,6 +1793,7 @@ azalia_widget_print_audio(const widget_t *this, const char *lead) int azalia_widget_init_pin(widget_t *this, const codec_t *codec) { + codec_t *wcodec; uint32_t result; int err; @@ -1939,6 +1836,14 @@ azalia_widget_init_pin(widget_t *this, const codec_t *codec) CORB_SET_PIN_WIDGET_CONTROL, result, NULL); } } + /* sense pin */ + if (codec->nsense_pins < AZ_MAX_SENSE_PINS && + this->d.pin.cap & COP_PINCAP_PRESENCE && + CORB_CD_PORT(this->d.pin.config) == CORB_CD_JACK) { + wcodec = &codec->az->codecs[codec->az->codecno]; + wcodec->sense_pins[codec->nsense_pins] = this->nid; + wcodec->nsense_pins++; + } return 0; } diff --git a/sys/dev/pci/azalia.h b/sys/dev/pci/azalia.h index 4633b7d2f82..1d00df8e5fc 100644 --- a/sys/dev/pci/azalia.h +++ b/sys/dev/pci/azalia.h @@ -1,4 +1,4 @@ -/* $OpenBSD: azalia.h,v 1.20 2008/11/05 03:20:35 jakemsr Exp $ */ +/* $OpenBSD: azalia.h,v 1.21 2008/11/19 03:44:14 jakemsr Exp $ */ /* $NetBSD: azalia.h,v 1.6 2006/01/16 14:15:26 kent Exp $ */ /*- @@ -474,6 +474,7 @@ #define CORB_NID_ROOT 0 #define HDA_MAX_CHANNELS 16 +#define AZ_MAX_SENSE_PINS 8 /* memory-mapped types */ typedef struct { @@ -556,6 +557,7 @@ typedef struct { #define MI_TARGET_SPDIF 0x107 #define MI_TARGET_SPDIF_CC 0x108 #define MI_TARGET_EAPD 0x109 +#define AZ_TARGET_PINSENSE 0xf00 } mixer_item_t; #define VALID_WIDGET_NID(nid, codec) (nid == (codec)->audiofunc || \ @@ -616,6 +618,9 @@ typedef struct codec_t { struct audio_encoding* encs; int nencs; + nid_t sense_pins[AZ_MAX_SENSE_PINS]; + int nsense_pins; + uint32_t *extra; u_int rate; } codec_t; diff --git a/sys/dev/pci/azalia_codec.c b/sys/dev/pci/azalia_codec.c index 860c54427e2..f1000e32314 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.65 2008/11/17 00:42:53 jakemsr Exp $ */ +/* $OpenBSD: azalia_codec.c,v 1.66 2008/11/19 03:44:14 jakemsr Exp $ */ /* $NetBSD: azalia_codec.c,v 1.8 2006/05/10 11:17:27 kent Exp $ */ /*- @@ -881,6 +881,35 @@ azalia_generic_mixer_init(codec_t *this) } } + /* sense pins */ + for (i = 0; i < this->nsense_pins; i++) { + FOR_EACH_WIDGET(this, j) { + if (this->w[j].nid == this->sense_pins[i]) + break; + } + if (j == this->wend) { + DPRINTF(("%s: sense pin %2.2x not found\n", + __func__, this->sense_pins[i])); + continue; + } + + MIXER_REG_PROLOG; + m->nid = this->w[j].nid; + snprintf(d->label.name, sizeof(d->label.name), "%s_sense", + this->w[j].name); + d->type = AUDIO_MIXER_ENUM; + d->mixer_class = AZ_CLASS_OUTPUT; + m->target = AZ_TARGET_PINSENSE; + d->un.e.num_mem = 2; + d->un.e.member[0].ord = 0; + strlcpy(d->un.e.member[0].label.name, "unplugged", + MAX_AUDIO_DEV_LEN); + d->un.e.member[1].ord = 1; + strlcpy(d->un.e.member[1].label.name, "plugged", + MAX_AUDIO_DEV_LEN); + this->nmixers++; + } + /* if the codec has multiple DAC groups, create "inputs.usingdac" */ if (this->dacs.ngroups > 1) { MIXER_REG_PROLOG; @@ -1367,6 +1396,15 @@ azalia_generic_mixer_get(const codec_t *this, nid_t nid, int target, mixer_ctrl_ mc->un.ord = result & CORB_EAPD_EAPD ? 1 : 0; } + /* sense pin */ + else if (target == AZ_TARGET_PINSENSE) { + err = this->comresp(this, nid, CORB_GET_PIN_SENSE, + 0, &result); + if (err) + return err; + mc->un.ord = result & CORB_PS_PRESENCE ? 1 : 0; + } + else { printf("%s: internal error in %s: target=%x\n", XNAME(this), __func__, target); @@ -1648,6 +1686,10 @@ azalia_generic_mixer_set(codec_t *this, nid_t nid, int target, const mixer_ctrl_ return err; } + else if (target == AZ_TARGET_PINSENSE) { + /* do nothing, control is read only */ + } + else { printf("%s: internal error in %s: target=%x\n", XNAME(this), __func__, target); |