[PATCH] ALSA: hda - bind headset buttons to the headphone jack

Takashi Iwai tiwai at suse.de
Wed Mar 3 09:46:35 CET 2021


On Wed, 03 Mar 2021 02:23:46 +0100,
Hui Wang wrote:
> 
> With the HDA driver, if the headset buttons are supported, an audio
> Jack will be created for them. This audio Jack is a bit confusing to
> users since it can't report headphone/mic insertion events but it
> claims to support these events.
> 
> And in addition, the driver already builds a headphone Jack and a mic
> Jack, and most of those buttons are used for headphone playback, so
> do some change to bind those buttons to the headphone Jack. After this
> change, the key events are generated from NID 0x55, and are reported
> to the input layer via headphone jack (NID 0x21).
> 
> If there is no headphone Jack, then build an audio jack to support
> those buttons same as previously.
> 
> Signed-off-by: Hui Wang <hui.wang at canonical.com>
> ---
>  sound/pci/hda/hda_jack.c      | 43 ++++++++++++++++++++++++++++++++++-
>  sound/pci/hda/hda_jack.h      |  5 ++++
>  sound/pci/hda/patch_realtek.c | 23 ++++++++++++++++---
>  3 files changed, 67 insertions(+), 4 deletions(-)
> 
> diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c
> index b8b568046592..640b72b598e8 100644
> --- a/sound/pci/hda/hda_jack.c
> +++ b/sound/pci/hda/hda_jack.c
> @@ -388,6 +388,39 @@ int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid,
>  }
>  EXPORT_SYMBOL_GPL(snd_hda_jack_set_gating_jack);
>  
> +/**
> + * snd_hda_jack_bind_keymap - bind keys generated from one NID to another jack.
> + * @codec: the HDA codec
> + * @key_nid: key event is generated by this pin NID
> + * @keymap: map of key type and key code
> + * @jack_nid: key reports to the jack of this pin NID
> + *
> + * This function is used in the case of key is generated from one NID while is
> + * reported to the jack of another NID.
> + */
> +int snd_hda_jack_bind_keymap(struct hda_codec *codec, hda_nid_t key_nid,
> +			     const struct hda_jack_keymap *keymap,
> +			     hda_nid_t jack_nid)
> +{
> +	const struct hda_jack_keymap *map;
> +	struct hda_jack_tbl *key_gen = snd_hda_jack_tbl_get(codec, key_nid);
> +	struct hda_jack_tbl *report_to = snd_hda_jack_tbl_get(codec, jack_nid);
> +
> +	WARN_ON(codec->dp_mst);
> +
> +	if (!key_gen || !report_to || !report_to->jack)
> +		return -EINVAL;
> +
> +	key_gen->key_report_jack = jack_nid;
> +
> +	if (keymap)
> +		for (map = keymap; map->type; map++)
> +			snd_jack_set_key(report_to->jack, map->type, map->key);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(snd_hda_jack_bind_keymap);
> +
>  /**
>   * snd_hda_jack_report_sync - sync the states of all jacks and report if changed
>   * @codec: the HDA codec
> @@ -651,7 +684,15 @@ void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res)
>  	}
>  	if (!event)
>  		return;
> -	event->jack_dirty = 1;
> +
> +	if (event->key_report_jack) {
> +		struct hda_jack_tbl *report_to =
> +			snd_hda_jack_tbl_get_mst(codec, event->key_report_jack,
> +						 event->dev_id);
> +		if (report_to)
> +			report_to->jack_dirty = 1;
> +	} else
> +		event->jack_dirty = 1;
>  
>  	call_jack_callback(codec, res, event);
>  	snd_hda_jack_report_sync(codec);
> diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h
> index 8ceaf0ef5df1..339746dd9578 100644
> --- a/sound/pci/hda/hda_jack.h
> +++ b/sound/pci/hda/hda_jack.h
> @@ -40,6 +40,7 @@ struct hda_jack_tbl {
>  	unsigned int block_report:1;    /* in a transitional state - do not report to userspace */
>  	hda_nid_t gating_jack;		/* valid when gating jack plugged */
>  	hda_nid_t gated_jack;		/* gated is dependent on this jack */
> +	hda_nid_t key_report_jack;	/* key reports to this jack */
>  	int type;
>  	int button_state;
>  	struct snd_jack *jack;
> @@ -99,6 +100,10 @@ snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid,
>  int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid,
>  				 hda_nid_t gating_nid);
>  
> +int snd_hda_jack_bind_keymap(struct hda_codec *codec, hda_nid_t key_nid,
> +			     const struct hda_jack_keymap *keymap,
> +			     hda_nid_t jack_nid);
> +
>  u32 snd_hda_jack_pin_sense(struct hda_codec *codec, hda_nid_t nid, int dev_id);
>  
>  /* the jack state returned from snd_hda_jack_detect_state() */
> diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
> index 52907506e16e..f381474f9403 100644
> --- a/sound/pci/hda/patch_realtek.c
> +++ b/sound/pci/hda/patch_realtek.c
> @@ -3102,6 +3102,16 @@ static void alc_headset_btn_callback(struct hda_codec *codec,
>  	if (jack->unsol_res & (7 << 10))
>  		report |= SND_JACK_BTN_3;
>  
> +	if (jack->jack->key_report_jack) {
> +		struct hda_jack_tbl *report_to =
> +			snd_hda_jack_tbl_get(codec, jack->jack->key_report_jack);
> +
> +		if (report_to) {
> +			report_to->button_state = report;
> +			return;
> +		}
> +	}
> +
>  	jack->jack->button_state = report;
>  }

I think this part should be rather in hda_jack.c, e.g. create a function
snd_hda_jack_set_button_state() and handle the redirection there.
It's not good to change the content in jack->jack externally.


thanks,

Takashi


More information about the Alsa-devel mailing list