[alsa-devel] [PATCH 1/2] ALSA: hda - Allow jack state to depend on another jack.
Takashi Iwai
tiwai at suse.de
Mon Nov 19 21:29:01 CET 2012
At Mon, 19 Nov 2012 09:36:21 -0800,
Dylan Reid wrote:
>
> On Mon, Nov 19, 2012 at 2:55 AM, Takashi Iwai <tiwai at suse.de> wrote:
> > At Sun, 18 Nov 2012 22:56:39 -0800,
> > Dylan Reid wrote:
> >>
> >> Introduce the concept of a "gated" jack. The gated jack's pin sense is
> >> only valid when the "gating" jack is plugged. This requires checking
> >> the gating jack when the gated jack changes and re-checking the gated
> >> jack when the gating jack is plugged/unplugged.
> >>
> >> This allows handling of devices where the mic jack detect floats when
> >> the headphone jack is unplugged.
> >
> > The snd_array stuff may reallocate the whole chunks, so you can't keep
> > the pointers pointing to the array elements. Instead of that, NIDs
> > should be kept and resolve on demand.
> >
> > In addition to that...
> >
> >>
> >> Signed-off-by: Dylan Reid <dgreid at chromium.org>
> >> ---
> >> sound/pci/hda/hda_jack.c | 46 ++++++++++++++++++++++++++++++++++++++++++++--
> >> sound/pci/hda/hda_jack.h | 4 ++++
> >> 2 files changed, 48 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c
> >> index 5bdbada..e851d88 100644
> >> --- a/sound/pci/hda/hda_jack.c
> >> +++ b/sound/pci/hda/hda_jack.c
> >> @@ -122,6 +122,8 @@ void snd_hda_jack_tbl_clear(struct hda_codec *codec)
> >> snd_array_free(&codec->jacktbl);
> >> }
> >>
> >> +#define get_jack_plug_state(sense) !!(sense & AC_PINSENSE_PRESENCE)
> >> +
> >> /* update the cached value and notification flag if needed */
> >> static void jack_detect_update(struct hda_codec *codec,
> >> struct hda_jack_tbl *jack)
> >> @@ -134,6 +136,27 @@ static void jack_detect_update(struct hda_codec *codec,
> >> else
> >> jack->pin_sense = read_pin_sense(codec, jack->nid);
> >>
> >> + /* A gating jack indicates the jack is invalid if gating is unplugged */
> >> + if (jack->gating_jack &&
> >> + !get_jack_plug_state(jack->gating_jack->pin_sense))
> >> + jack->pin_sense &= ~AC_PINSENSE_PRESENCE;
> >> +
> >> + /* If a jack is gated by this one update it. */
> >> + if (jack->gated_jack) {
> >> + struct hda_jack_tbl *gated = jack->gated_jack;
> >> +
> >> + if (gated->callback)
> >> + gated->callback(codec, gated);
> >
> > I don't think this is the right place to call the callback of the
> > gated pin. It should be called where the callback of gating pin is
> > called.
> >
> >> + /* If this jack is plugged, then check the gated jack, otherwise
> >> + * not plugged.
> >> + */
> >> + if (get_jack_plug_state(jack->pin_sense))
> >> + gated->pin_sense = read_pin_sense(codec, gated->nid);
> >> + else
> >> + gated->pin_sense &= ~AC_PINSENSE_PRESENCE;
> >> + }
> >
> > ... and the handling of gated pin can be done more easily by calling
> > jack_detect_update() again.
> >
> > And, another place to fix is the jack sync code.
> > Since now you have a dependency between jacks, the update and check have
> > to be split to two: update all jacks, and call jack sync for each
> > pin. Otherwise, it won't be handled properly if a gating jack appears
> > in the table after a gated jack.
> >
> > The below is my revised patch. Could you check it?
>
> Tested, works great. Thanks for looking and fixing Takashi.
OK, merged both patches now to for-next branch.
thanks,
Takashi
>
> -Dylan
>
> >
> >
> > thanks,
> >
> > Takashi
> >
> > ---
> > diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c
> > index 5bdbada..4e19480 100644
> > --- a/sound/pci/hda/hda_jack.c
> > +++ b/sound/pci/hda/hda_jack.c
> > @@ -122,6 +122,8 @@ void snd_hda_jack_tbl_clear(struct hda_codec *codec)
> > snd_array_free(&codec->jacktbl);
> > }
> >
> > +#define get_jack_plug_state(sense) !!(sense & AC_PINSENSE_PRESENCE)
> > +
> > /* update the cached value and notification flag if needed */
> > static void jack_detect_update(struct hda_codec *codec,
> > struct hda_jack_tbl *jack)
> > @@ -134,7 +136,21 @@ static void jack_detect_update(struct hda_codec *codec,
> > else
> > jack->pin_sense = read_pin_sense(codec, jack->nid);
> >
> > + /* A gating jack indicates the jack is invalid if gating is unplugged */
> > + if (jack->gating_jack && !snd_hda_jack_detect(codec, jack->gating_jack))
> > + jack->pin_sense &= ~AC_PINSENSE_PRESENCE;
> > +
> > jack->jack_dirty = 0;
> > +
> > + /* If a jack is gated by this one update it. */
> > + if (jack->gated_jack) {
> > + struct hda_jack_tbl *gated =
> > + snd_hda_jack_tbl_get(codec, jack->gated_jack);
> > + if (gated) {
> > + gated->jack_dirty = 1;
> > + jack_detect_update(codec, gated);
> > + }
> > + }
> > }
> >
> > /**
> > @@ -173,8 +189,6 @@ u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid)
> > }
> > EXPORT_SYMBOL_HDA(snd_hda_pin_sense);
> >
> > -#define get_jack_plug_state(sense) !!(sense & AC_PINSENSE_PRESENCE)
> > -
> > /**
> > * snd_hda_jack_detect - query pin Presence Detect status
> > * @codec: the CODEC to sense
> > @@ -222,16 +236,46 @@ int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid,
> > EXPORT_SYMBOL_HDA(snd_hda_jack_detect_enable);
> >
> > /**
> > + * snd_hda_jack_set_gating_jack - Set gating jack.
> > + *
> > + * Indicates the gated jack is only valid when the gating jack is plugged.
> > + */
> > +int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid,
> > + hda_nid_t gating_nid)
> > +{
> > + struct hda_jack_tbl *gated = snd_hda_jack_tbl_get(codec, gated_nid);
> > + struct hda_jack_tbl *gating = snd_hda_jack_tbl_get(codec, gating_nid);
> > +
> > + if (!gated || !gating)
> > + return -EINVAL;
> > +
> > + gated->gating_jack = gating_nid;
> > + gating->gated_jack = gated_nid;
> > +
> > + return 0;
> > +}
> > +EXPORT_SYMBOL_HDA(snd_hda_jack_set_gating_jack);
> > +
> > +/**
> > * snd_hda_jack_report_sync - sync the states of all jacks and report if changed
> > */
> > void snd_hda_jack_report_sync(struct hda_codec *codec)
> > {
> > - struct hda_jack_tbl *jack = codec->jacktbl.list;
> > + struct hda_jack_tbl *jack;
> > int i, state;
> >
> > + /* update all jacks at first */
> > + jack = codec->jacktbl.list;
> > for (i = 0; i < codec->jacktbl.used; i++, jack++)
> > - if (jack->nid) {
> > + if (jack->nid)
> > jack_detect_update(codec, jack);
> > +
> > + /* report the updated jacks; it's done after updating all jacks
> > + * to make sure that all gating jacks properly have been set
> > + */
> > + jack = codec->jacktbl.list;
> > + for (i = 0; i < codec->jacktbl.used; i++, jack++)
> > + if (jack->nid) {
> > if (!jack->kctl)
> > continue;
> > state = get_jack_plug_state(jack->pin_sense);
> > @@ -424,6 +468,19 @@ int snd_hda_jack_add_kctls(struct hda_codec *codec,
> > }
> > EXPORT_SYMBOL_HDA(snd_hda_jack_add_kctls);
> >
> > +static void call_jack_callback(struct hda_codec *codec,
> > + struct hda_jack_tbl *jack)
> > +{
> > + if (jack->callback)
> > + jack->callback(codec, jack);
> > + if (jack->gated_jack) {
> > + struct hda_jack_tbl *gated =
> > + snd_hda_jack_tbl_get(codec, jack->gated_jack);
> > + if (gated && gated->callback)
> > + gated->callback(codec, gated);
> > + }
> > +}
> > +
> > void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res)
> > {
> > struct hda_jack_tbl *event;
> > @@ -434,9 +491,7 @@ void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res)
> > return;
> > event->jack_dirty = 1;
> >
> > - if (event->callback)
> > - event->callback(codec, event);
> > -
> > + call_jack_callback(codec, event);
> > snd_hda_jack_report_sync(codec);
> > }
> > EXPORT_SYMBOL_HDA(snd_hda_jack_unsol_event);
> > @@ -455,8 +510,7 @@ void snd_hda_jack_poll_all(struct hda_codec *codec)
> > if (old_sense == get_jack_plug_state(jack->pin_sense))
> > continue;
> > changes = 1;
> > - if (jack->callback)
> > - jack->callback(codec, jack);
> > + call_jack_callback(codec, jack);
> > }
> > if (changes)
> > snd_hda_jack_report_sync(codec);
> > diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h
> > index 4487785..ec12abd 100644
> > --- a/sound/pci/hda/hda_jack.h
> > +++ b/sound/pci/hda/hda_jack.h
> > @@ -28,6 +28,8 @@ struct hda_jack_tbl {
> > unsigned int jack_detect:1; /* capable of jack-detection? */
> > unsigned int jack_dirty:1; /* needs to update? */
> > unsigned int phantom_jack:1; /* a fixed, always present port? */
> > + hda_nid_t gating_jack; /* valid when gating jack plugged */
> > + hda_nid_t gated_jack; /* gated is dependent on this jack */
> > struct snd_kcontrol *kctl; /* assigned kctl for jack-detection */
> > #ifdef CONFIG_SND_HDA_INPUT_JACK
> > int type;
> > @@ -69,6 +71,8 @@ int snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid,
> > unsigned char action,
> > hda_jack_callback cb);
> >
> > +int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid,
> > + hda_nid_t gating_nid);
> >
> > u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid);
> > int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid);
>
More information about the Alsa-devel
mailing list