[alsa-devel] [PATCH 1/2] ALSA: hda - Allow jack state to depend on another jack.

Dylan Reid dgreid at chromium.org
Mon Nov 19 18:36:21 CET 2012


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.

-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