[alsa-devel] [PATCH v4] ALSA: hdmi: expose ELD control

Takashi Iwai tiwai at suse.de
Mon Oct 3 15:49:03 CEST 2011


At Fri, 30 Sep 2011 16:35:41 -0500,
Pierre-Louis Bossart wrote:
> 
> Applications may want to read ELD information to
> understand what codecs are supported on the HDMI
> receiver and handle the a-v delay for better lip-sync.
> 
> ELD information is exposed in a device-specific
> IFACE_PCM kcontrol. Tested both with amixer and
> PulseAudio; with a corresponding patch passthrough modes
> are enabled automagically.
> 
> ELD control size is set to zero in case of errors or
> wrong configurations. No notifications are implemented
> for now, it is expected that jack detection is used to
> reconfigure the audio outputs.
> 
> Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart at linux.intel.com>

Thanks, applied now.


Takashi

> ---
>  sound/pci/hda/hda_eld.c    |   13 +++++---
>  sound/pci/hda/hda_local.h  |    2 +
>  sound/pci/hda/patch_hdmi.c |   68 ++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 78 insertions(+), 5 deletions(-)
> 
> diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c
> index c34f730..f1c621d 100644
> --- a/sound/pci/hda/hda_eld.c
> +++ b/sound/pci/hda/hda_eld.c
> @@ -318,6 +318,11 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld,
>  	int size;
>  	unsigned char *buf;
>  
> +	/*
> +	 * ELD size is initialized to zero in caller function. If no errors and
> +	 * ELD is valid, actual eld_size is assigned in hdmi_update_eld()
> +	 */
> +
>  	if (!eld->eld_valid)
>  		return -ENOENT;
>  
> @@ -327,14 +332,13 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld,
>  		snd_printd(KERN_INFO "HDMI: ELD buf size is 0, force 128\n");
>  		size = 128;
>  	}
> -	if (size < ELD_FIXED_BYTES || size > PAGE_SIZE) {
> +	if (size < ELD_FIXED_BYTES || size > ELD_MAX_SIZE) {
>  		snd_printd(KERN_INFO "HDMI: invalid ELD buf size %d\n", size);
>  		return -ERANGE;
>  	}
>  
> -	buf = kmalloc(size, GFP_KERNEL);
> -	if (!buf)
> -		return -ENOMEM;
> +	/* set ELD buffer */
> +	buf = eld->eld_buffer;
>  
>  	for (i = 0; i < size; i++) {
>  		unsigned int val = hdmi_get_eld_data(codec, nid, i);
> @@ -356,7 +360,6 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld,
>  	ret = hdmi_update_eld(eld, buf, size);
>  
>  error:
> -	kfree(buf);
>  	return ret;
>  }
>  
> diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
> index aaefa7c..04d730f 100644
> --- a/sound/pci/hda/hda_local.h
> +++ b/sound/pci/hda/hda_local.h
> @@ -621,6 +621,7 @@ struct cea_sad {
>  };
>  
>  #define ELD_FIXED_BYTES	20
> +#define ELD_MAX_SIZE    256
>  #define ELD_MAX_MNL	16
>  #define ELD_MAX_SAD	16
>  
> @@ -645,6 +646,7 @@ struct hdmi_eld {
>  	int	spk_alloc;
>  	int	sad_count;
>  	struct cea_sad sad[ELD_MAX_SAD];
> +	char    eld_buffer[ELD_MAX_SIZE];
>  #ifdef CONFIG_PROC_FS
>  	struct snd_info_entry *proc_entry;
>  #endif
> diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
> index 3f1f6ac..3425401 100644
> --- a/sound/pci/hda/patch_hdmi.c
> +++ b/sound/pci/hda/patch_hdmi.c
> @@ -324,6 +324,66 @@ static int cvt_nid_to_cvt_index(struct hdmi_spec *spec, hda_nid_t cvt_nid)
>  	return -EINVAL;
>  }
>  
> +static int hdmi_eld_ctl_info(struct snd_kcontrol *kcontrol,
> +			struct snd_ctl_elem_info *uinfo)
> +{
> +	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
> +	struct hdmi_spec *spec;
> +	int pin_idx;
> +
> +	spec = codec->spec;
> +	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
> +
> +	pin_idx = kcontrol->private_value;
> +	uinfo->count = spec->pins[pin_idx].sink_eld.eld_size;
> +
> +	return 0;
> +}
> +
> +static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol,
> +			struct snd_ctl_elem_value *ucontrol)
> +{
> +	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
> +	struct hdmi_spec *spec;
> +	int pin_idx;
> +
> +	spec = codec->spec;
> +	pin_idx = kcontrol->private_value;
> +
> +	memcpy(ucontrol->value.bytes.data,
> +		spec->pins[pin_idx].sink_eld.eld_buffer, ELD_MAX_SIZE);
> +
> +	return 0;
> +}
> +
> +static struct snd_kcontrol_new eld_bytes_ctl = {
> +	.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
> +	.iface = SNDRV_CTL_ELEM_IFACE_PCM,
> +	.name = "ELD",
> +	.info = hdmi_eld_ctl_info,
> +	.get = hdmi_eld_ctl_get,
> +};
> +
> +static int hdmi_create_eld_ctl(struct hda_codec *codec, int pin_idx,
> +			int device)
> +{
> +	struct snd_kcontrol *kctl;
> +	struct hdmi_spec *spec = codec->spec;
> +	int err;
> +
> +	kctl = snd_ctl_new1(&eld_bytes_ctl, codec);
> +	if (!kctl)
> +		return -ENOMEM;
> +	kctl->private_value = pin_idx;
> +	kctl->id.device = device;
> +
> +	err = snd_hda_ctl_add(codec, spec->pins[pin_idx].pin_nid, kctl);
> +	if (err < 0)
> +		return err;
> +
> +	return 0;
> +}
> +
>  #ifdef BE_PARANOID
>  static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t pin_nid,
>  				int *packet_index, int *byte_index)
> @@ -1193,6 +1253,14 @@ static int generic_hdmi_build_controls(struct hda_codec *codec)
>  		if (err < 0)
>  			return err;
>  		snd_hda_spdif_ctls_unassign(codec, pin_idx);
> +
> +		/* add control for ELD Bytes */
> +		err = hdmi_create_eld_ctl(codec,
> +					pin_idx,
> +					spec->pcm_rec[pin_idx].device);
> +
> +		if (err < 0)
> +			return err;
>  	}
>  
>  	return 0;
> -- 
> 1.7.6.2
> 
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel at alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
> 


More information about the Alsa-devel mailing list