[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